• 函数
    • Function Call
    • Function Define
    • Overloading
    • Variable arguments
    • Destructuring
    • Body
    • 匿名函数

    函数

    Clojure是一门函数式编程语言,function具有非常重要的地位。

    Function Call

    函数调用很简单,我们已经见过了很多例子:

    1. (+ 1 2 3)
    2. (* 1 2 3)

    我们也可以将函数返回让外面使用:

    1. user=> ((or + -) 1 2 3)
    2. 6

    如果我们调用了非法的函数,会报错:

    1. user=> (1 2 3)
    2. ClassCastException java.lang.Long cannot be cast to clojure.lang.IFn user/eval1491 (form-init7840101683239336203.clj:1)

    这里,1并不是一个合法的operator

    Function Define

    一个函数,通常由几个部分组成:

    1. defn
    2. 函数名称
    3. 函数说明(可选)
    4. 参数列表,使用[]封装
    5. 函数body

    一个例子:

    1. user=> (defn fun1
    2. #_=> "a function example"
    3. #_=> [name]
    4. #_=> (str "hello " name))
    5. #'user/fun1
    6. user=> (fun1 "world")
    7. "hello world"
    8. user=> (doc fun1)
    9. -------------------------
    10. user/fun1
    11. ([name])
    12. a function example
    13. nil

    Overloading

    我们也可以进行函数重载,如下:

    1. user=> (defn func-multi
    2. #_=> ([](str "no arg"))
    3. #_=> ([name1](str "arg " name1))
    4. #_=> ([name1 name2](str "arg " name1 " " name2)))
    5. user=> (func-multi)
    6. "no arg"
    7. user=> (func-multi "1")
    8. "arg 1"
    9. user=> (func-multi "1" "2")
    10. "arg 1 2"

    Variable arguments

    我们使用&来支持可变参数

    1. user=> (defn func-args
    2. #_=> [name & names]
    3. #_=> (str name " " (clojure.string/join " " names)))
    4. #'user/func-args
    5. user=> (func-args "a")
    6. "a "
    7. user=> (func-args "a" "b")
    8. "a b"
    9. user=> (func-args "a" "b" "c")
    10. "a b c"

    Destructuring

    我们可以在函数参数里面通过特定的name来获取对应的collection的数据,譬如:

    1. user=> (defn f-vec1 [[a]] [a])
    2. #'user/f-vec1
    3. user=> (f-vec1 [1 2 3])
    4. [1]
    5. user=> (defn f-vec2 [[a b]] [a b])
    6. #'user/f-vec2
    7. user=> (f-vec2 [1 2 3])
    8. [1 2]

    在上面的例子里面,我们的参数是一个vector,然后[a]以及[a b]表示,我们需要获取这个vector里面的第一个以及第二个数据,并且使用变量a,b存储。

    我们也可以使用map,譬如:

    1. user=> (defn f-map [{a :a b :b}] [a b])
    2. #'user/f-map
    3. user=> (f-map {:a 1 :b 2})
    4. [1 2]
    5. user=> (f-map {:a 1 :c 2})
    6. [1 nil]

    上面这个例子我们可以用:keys来简化,

    1. user=> (defn f-map-2 [{:keys [a b]}] [a b])
    2. #'user/f-map-2
    3. user=> (f-map-2 {:a 1 :b 2 :c 3})
    4. [1 2]

    我们可以通过:as来获取原始的map:

    1. user=> (defn f-map-3 [{:keys [a b] :as m}] [a b (:c m)])
    2. #'user/f-map-3
    3. user=> (f-map-3 {:a 1 :b 2 :c 3})
    4. [1 2 3]

    Body

    Functionbody里面可以包括多个formClojure会将最后一个form执行的值作为该函数的返回值:

    1. user=> (defn func-body []
    2. #_=> (+ 1 2)
    3. #_=> (+ 2 3))
    4. #'user/func-body
    5. user=> (func-body)
    6. 5

    匿名函数

    我们可以通过fn来声明一个匿名函数

    1. user=> ((fn [name] (str "hello " name)) "world")
    2. "hello world"

    我们也可以通过def来给一个匿名函数设置名称:

    1. user=> (def a (fn [name] (str "hello " name)))
    2. #'user/a
    3. user=> (a "world")
    4. "hello world"

    当然,我们更加简化匿名函数,如下:

    1. user=> #(str "hello " %)
    2. #object[user$eval1584$fn__1585 0x72445715 "user$eval1584$fn__1585@72445715"]
    3. user=> (#(str "hello " %) "world")
    4. "hello world"

    我们使用%来表明匿名函数的参数,如果有多个参数,则使用%1%2来获取,使用%&来获取可变参数。

    1. user=> (#(str "hello " %) "world")
    2. "hello world"
    3. user=> (#(str "hello " %1 " " %2) "world" "a ha")
    4. "hello world a ha"
    5. user=> (#(str "hello " %1 " " (clojure.string/join " " %&)) "world" "ha" "ha")
    6. "hello world ha ha"