Clojure 解构

what & why

解构是用来方便赋值的,否则获取值的时候就要使用大量的next ,first 之类的 seq 操作,不方便,尤其是嵌套的 collection,取值就更麻烦。

有了解构以后,把collection 的值取出来就非常的简单和方便,除了可以用于let以外,还可以用于函数参数的赋值等地方

Clojure的解构特性提供了一种简洁的语法来声明式地从一个集合里面选取某些元素,并且把这些元素绑定到一个本地let绑定上去。并且因为解构这个特性是由let提供的, 它可以在任何间接使用了let的地方使用,比如fn、defn、loop。

how

1 list或vector解构

(let [[a b c] [1 2 3]]
    (println a ", " b ", " c))
;=> 1, 2, 3
;你可以看到let的中括号中对应的关系
[
    [a b c] 
    [1 2 3]
]
(let [[a [b [c]]] [1 [2 [3]]]]
    (println a ", " b ", " c))
;=> 1, 2, 3
[
    [a [b [c]]] 
    [1 [2 [3]]]
]

如果有的值不需要,但是又需要展位,clojure 中有一个惯用法 _ 下划线,来占用,但是不使用他的值。用下划线的方式来忽略掉一个或多个自己不在意的值。

(let [[a [_ [c]]] [1 [2 [3]]]]
    (println a ", " c))
;=> 1, 2, 3

可以看到,只需要我们的取值的解构和原始数据结构一致,就可以很方便的把值一次取到,方便使用。

2 & 获取剩余值,& 符号会把剩下的值以list的形式全部放入b中,

(let [[a & b] [1 2 3]]
    (println a ", " b))
;=> 1, (2 3)

3 :as 可以在解构形式中使用:as来获得对于被解构的集合的引用


(let [[a & b :as c] [1 2 3]]
    (println (a ", " b ", " c)))
;=> 1, (2 3), [1 2 3]

4 map的解构

(let [{a :a b :b c :c} {:a 1 :b 2 :c 3}]
  (println a ", " b ", " c))
;=> 1, 2, 3

map 的解构是用关键字来对应右边的关键字,然后把值给了 a 符号

跟顺序解构一样,map解构也可以处理内嵌map:

要注意的是,可以在map解构中用做key的不止是关键字,可以是任何类型的值,比如字符串:

当key找不到值的时候,就默认值为nil, 可以使用:or关键字来提供一个默认值

:or能区分到底是没有赋值,还是赋给的值就是逻辑false(nil或者false)

map引用的简便方法

(let [{:keys [a b c]} {:a 1 :b 2 :c 3}]
  (pritnln a ", " b ", " c))
;=> 1, 2, 3

(let [{foo "foo" aaa :bbb :or {aaa 50}} m]
  (println foo aaa))

使用:keys关键字告诉clojure,接下来的是一个vector,里面的每一个元素当做关键字去右边map里面找到对应的值,找到的值就直接给这个符号

同样的还有:strs关键字和:syms

:keys表示key的类型是关键字;:strs表示key的类型是字符串;:syms表示key的类型是符号

在map解构中,同样可以使用:as all

&关键字在 map 中如何使用呢?map解构中不可以使用&关键字

5 vector也可以使用 map 的方式来解构

(let [{b 1 c 2 } [1 2 3]]
  (println b ", " c))
;=> 2, 3

{% raw %}

(def m {:a 5 :b 6 :c [7 8 9] :d {:e 10 :f 11} "foo" 88 42 false})

(let [{foo "foo"} m]
  (println foo))

(let [{f 42} m]
  (println f))


(let [{v 42} m]
  (if v 1 0))

(let [{{e :e} :d} m]
  (println e))

; 把顺序解构和map解构结合起来
(let [{[x y _] :c} m]
  (println x y))

{% endraw %}

把vector中的下标和要对应的符号在 map 中一一对应起来,值就可以赋值过去

Clojure提供的更好的办法是直接用map解构来解构集合的剩余部分——如果剩余部分的元素个数是偶数的话,顺序解构会把剩余部分当做一个map来处理,神奇吧?

(let[[username account-year & {:keys [name city]}] user-info]
(format "%s is in %s" name city))
;="Bob is in Boston"

2018-12-30 08:55

留言