我已经尝试过1.7.0和1.8.0,看起来Clojure没有使用其键完全限定的:keys
来解构地图。我不认为它与参数的尾部有关,因为当我切换函数参数位置时它不起作用。
(ns foo.sandbox)
(def foo ::foo)
(def bar ::bar)
(defn normalize-vals
[mmap & [{:keys [foo bar] :as ops}]]
(println "normalize-vals " ops " and foo " foo " bar" bar))
(normalize-vals {} {foo 1 bar 2})
=> normalize-vals {:foo.sandbox/foo 1, :foo.sandbox/bar 2} and foo nil bar nil
然而;这有效:
(defn normalize-vals
[mmap & [{a foo b bar :as ops}]]
(println "normalize-vals " ops " and foo " a " bar" b))
(normalize-vals {} {foo 1 bar 2})
=> normalize-vals {:cmt.sandbox/foo 1, :cmt.sandbox/bar 2} and foo 1 bar 2
这是一个缺陷吗?
答案 0 :(得分:1)
让我们按原样执行您的功能:
(defn normalize-vals
[mmap & [{:keys [foo bar] :as ops}]]
(println "normalize-vals " ops " and foo " foo " bar" bar))
请注意foo
&上面的bar
是本地绑定,它们不引用函数之外的任何东西。
...并稍微重写其他代码:
(def foo-const ::foo)
(def bar-const ::bar)
不要过分关注这里的命名,重点是使用不同的名称。
(normalize-vals {} {foo 1 bar 2})
;; error: ...Unable to resolve symbol: foo in this context...
(normalize-vals {} {foo-const 1 bar-const 2})
;; prints: normalize-vals {:user/foo 1, :user/bar 2} and foo nil bar nil
课程应该是尽可能使用唯一的名称。
以解构形式{a foo b bar :as ops}
;
a
& b
是新的本地绑定。如果我们有一个名为a
或b
的var,则会在此函数的范围内覆盖它们。foo
& bar
已从环境中解析出来。如果我们不使用上面的-const
后缀,我们会得到CompilerException
,就像上面那样。答案 1 :(得分:0)
您使用非限定关键字进行解构,因此不是:
[mmap & [{:keys [foo bar] :as ops}]]
你应该使用
[mmap & [{:keys [::foo ::bar] :as ops}]]
您可以使用clojure.walk/macroexpand-all
展开normalize-vals
:
(clojure.walk/macroexpand-all '(defn normalize-vals
[mmap & [{:keys [foo bar] :as ops}]]
(println "normalize-vals " ops " and foo " foo " bar" bar)))
=> (def normalize-vals (fn* ([mmap & p__26720] (let* [vec__26721 p__26720 map__26722 (clojure.core/nth vec__26721 0 nil) map__26722 (if (clojure.core/seq? map__26722) (. clojure.lang.PersistentHashMap create (clojure.core/seq map__26722)) map__26722) ops map__26722 foo (clojure.core/get map__26722 :foo) bar (clojure.core/get map__26722 :bar)] (println "normalize-vals " ops " and foo " foo " bar" bar)))))
需要注意的扩展的重要部分是:
foo (clojure.core/get map__26722 :foo)
bar (clojure.core/get map__26722 :bar)
因此,地图解构中的键将转换为编译时的关键字,并且不会使用命名空间中foo和bar vars的值。