3

如果我评估

(def ^:macro my-defn1 #'defn)

定义了一个名为“my-defn1”的宏,我可以像使用“defn”一样使用它。

但是,如果我改为评估

(if true
  (def ^:macro my-defn2 #'defn))

'my-defn2' 的 var 没有 :macro 元数据集,我不能将它用作宏,即使 'def' 形式与前一种情况相同。

这是完整的代码(http://cljbin.com/paste/52322ba5e4b0fa645e7f9243):

(def ^:macro my-defn1 #'defn)

(if true
  (def ^:macro my-defn2 #'defn))

(println (meta #'my-defn1))    ; => contains :macro

(println (meta #'my-defn2))    ; => doesn't contain :macro!

(my-defn1 hello1 []
          (println "hello 1"))

(hello1)                       ; => prints "hello 1"

(my-defn2 hello2 []            ; => CompilerException: Unable to resolve 
  (println "hello 2"))         ;    symbol: hello2 in this context

是什么让行为不同?

4

1 回答 1

1

Clojure 的 def 不能真正有条件地应用。def 的文档在这方面不够强大。这不仅仅是糟糕的风格,它可能会导致各种微妙的问题。

您应该只在顶层使用 def ,或者在顶层使用 a door letform 。有条件地应用 def 将导致功能被分成类似的东西declare和随后的条件def,但并不总是以您期望/喜欢的方式。

您最好在此处的顶层使用 def ,然后有条件地使用alter-var-root. 或使用(def my-var (if .. .. ..)). 想想为什么你想要一个全局定义“消失”。

于 2013-09-16T06:59:10.350 回答