如果我评估
(def ^:macro my-defn1 #'defn)
定义了名为'my-defn1'的宏,我可以像'defn'一样使用。
但是,如果我评估
(if true
(def ^:macro my-defn2 #'defn))
'my-defn2'的var没有设置:宏元数据,我不能将它用作宏,即使'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
是什么让这种行为与众不同?
答案 0 :(得分:1)
Clojure的def不能真正有条件地应用。 def的文档是IMO在这方面不够强大。这不仅仅是糟糕的风格,它还会引发各种微妙的问题。
您应该只在顶层使用def,或者在顶层使用do
或let
表单。有条件地应用def会导致功能被分解为declare
和后续条件def
,但并不总是像您期望/喜欢的那样。
最好在顶级使用def,然后有条不紊地使用alter-var-root
。或者使用(def my-var (if .. .. ..))
。想想为什么你想要一个全局定义“消失”。