函数

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"