首页 > 代码库 > clojure的参数分解,Binding Forms (Destructuring)

clojure的参数分解,Binding Forms (Destructuring)

clojure的let参数分解,文档描述的很清楚。比如它举的例子

(let [[a b c & d :as e] [1 2 3 4 5 6 7]]
  [a b c d e])
 
->[1 2 3 (4 5 6 7) [1 2 3 4 5 6 7]]

这个let,使用其它语言的可以把它当作赋值。比如:java的 int i = 0,也有支持多变量赋值的,比如perl的 my ($a $b) = @a (不知对不对,就这个意思)。但是clojure变化更大。上面的例子中,最后赋值的结果就是->后面显示的。

(let [[a b & c :as str] "asdjhhfdas"]
  [a b c str])
 
->[\a \s (\d \j \h \h \f \d \a \s) "asdjhhfdas"]

string也一样,在clolure里面不都是seq嘛。

(let [{a :a, b :b, c :c, :as m :or {a 2 b 3}}  {:a 5 :c 6}]
  [a b c m])
 
->[5 3 6 {:c 6, :a 5}]

上面是解构map,:or的意思是,如果没有找到,就用默认,:b显然不在{:a 5 :c 6}中,所以最后的值是3。


函数参数的解构:

一般来说函数在定义的时候会指定参数,比如下面的参数,根据显示你呼叫该函数时参数的个数,我这里写到最多接收2个参数,根据Clojure文档描述,最多可以有20个参数(仅仅只这种显式申明的方式)。

(defn- fixargs
 ([] 0)
 ([_] 1)
 [_ _] 2))

如果你执行(fixargs :a :b :c),就会报错。当然我可以这样定义函数:这样不管你传入几个参数,这个函数都会将个数显示出来。但是至少需要2个参数,小于两个参数就会报错。如果把a b 删除,就可以接受任意(包括没有)个数了。

(defn- anyargs
    [a b & c]
    (+ 2 (count c)))

如果你偶尔看到下面这种类型的函数参数定义,可能会觉得困惑,不过clojure可以repl,所以测试一下就知道结果了。

(defn- hashp-p [a & {:b b}]
    [a b])

(hash-p 1 :b 2)  --------------> [1 2]

也就是说,你传入3个参数,a娶了第一个1,剩下2个是 :b 2,可见clojure将剩下的2个组成了一个map,对应解构出来就是2了。

如果你认为 [& c]会自动将vector变成map,那就又错了,让我们试一下。

(defn f-n [& c]
    (:b c))
;然后呼叫
(f-n :b 2) ---------->nil

clojure的代码咋一看毫无章法,习惯之后,它其实遵循非常简单统一的原则,都是form,求值,就这么两回事。(当然,就像Clojure文档中提到的,它持一种务实的态度,因此引入var,ref,atom,agent等,用相对自然的方式解决对应问题)

clojure的参数分解,Binding Forms (Destructuring)