destructure
您可以通过手动调用来查看幕后发生的事情。让我们从一个更简单的例子开始:
user> (destructure ['{foo :foo} {:foo 42}])
[map__26147 {:foo 42}
map__26147 (if (clojure.core/seq? map__26147)
(clojure.lang.PersistentHashMap/create
(clojure.core/seq map__26147))
map__26147)
foo (clojure.core/get map__26147 :foo)]
这对应于(let [{foo :foo} {:foo 42}] ...)
(你可以用(macroexpand-1 '(let [{foo :foo} {:foo 42}] ...))
. -map (好像 by (apply hash-map the-seq)
。否则,该值被假定为关联并直接使用。在此提交中添加了 seq 'pouring' 功能。
让我们测试一下:
user> (let [{foo :foo} {:foo 42}] foo)
42
user> (let [{foo :foo} (list :foo 42)] foo)
42
user> (let [{foo :foo} (apply hash-map (list :foo 42))] foo)
42
第一种情况,value不是seq,所以直接使用。在第二种情况下,列表是一个 seq,因此在绑定到{foo :foo}
. 第三种情况表明,这种倾倒在语义上等价于(apply hash-map the-seq)
。
现在让我们看一下您的示例:
user> (destructure '[[& {:keys [foo bar]}] args])
[vec__26204 args
map__26205 (clojure.core/nthnext vec__26204 0)
map__26205 (if (clojure.core/seq? map__26205)
(clojure.lang.PersistentHashMap/create
(clojure.core/seq map__26205))
map__26205)
bar (clojure.core/get map__26205 :bar)
foo (clojure.core/get map__26205 :foo)]
该nthnext
位来自&
- 在这种情况下,因为在 之前没有固定参数,所以&
我们有一个(nthnext vec# 0)
,这相当于只是转换args
为一个 seq (如果需要)。然后我们像上面那样解构地图。因为&
我们有一个 seq 的保证,所以映射解构的 seq 特例总是会被触发,并且在绑定到映射形式之前,args 总是会被“注入”到哈希映射中。
如果此示例与您的原始 fn 之间的关系不清楚,请考虑:
user> (macroexpand-1 '(fn [& {:keys [foo bar]}]))
(fn* ([& p__26214] (clojure.core/let [{:keys [foo bar]} p__26214])))