0

为什么在我执行defmultia之后when-not,以前未解析的符号解析得很好,但没有绑定到该值?

user=> (resolve 'buux)
nil

user=> (when-not (resolve 'buux) (defmulti buux class))
nil

user=> (resolve 'buux)
#'user/buux

user=> (bound? #'buux)
false

user=> (defmulti buux class)
#'user/buux

user=> (bound? #'buux)
true
4

1 回答 1

2

defmulti 将使用def用于定义符号的 let 块进行扩展。事实上,返回的表达式defmulti不会被计算,而是使用let生成的形式,因此,对象成为全局定义的。这会导致在定义 var 之后、创建 multi-fn 并且 var 的根绑定受到影响之前,您的测试条件(何时不成功)成功。您的 defmulti 块从未执行过(when-not 表达式也返回 nil),而是扩展了。

进一步说明:

在这里你可以看到这是如何发生的:

(macroexpand '(defmulti buxx class))

现在您可以看到宏调用将生成的表单:

(clojure.pprint/write (macroexpand '(defmulti buxx class))
                      :with-dispatch clojure.pprint/code-dispatch) 
=> 
(let*
 [v__4080__auto__ (def buxx)]
 (clojure.core/when-not
  (clojure.core/and
   (.hasRoot v__4080__auto__)
   (clojure.core/instance? clojure.lang.MultiFn @v__4080__auto__))
   ...

这导致(def buux)被扩展。如果您(def buux)在您的 repl 中进行评估,您可以进行相同的测试。

来自def的文档字符串:

def 产生 var 本身(不是它的值)。

这意味着,在扩展时,它被替换为(可能未绑定的)var。

因此,在扩展时,def 总是创建一个 var,但返回新值(对于 var)的可选形式将仅在评估扩展的 def 时进行评估。宏和特殊形式将在实际评估之前进行扩展。例如。测试

(defmacro i-have-side-effects
  []
  (println "I was invoked!")
  42)
(when-not true
  (println (i-have-side-effects)))

=>
#'user/i-have-side-effects
I was invoked!
nil

所以可能你不应该有条件地定义一个多方法。

于 2013-09-07T23:46:09.270 回答