我不清楚为什么在下面的代码片段中,foo是在"user"命名空间中定义的,而不是在绑定闭包中绑定到*ns*的那个.有人可以解释我错过的东西吗?
$ clj
Clojure 1.4.0
user=> (let [nspace (create-ns (gensym "sandbox"))]
(binding [*ns* nspace]
(print (ns-name *ns*))
(def foo 6)))
sandbox3#'user/foo
user=> foo
6
user=> (in-ns 'sandbox3)
#
sandbox3=> foo
CompilerException java.lang.RuntimeException: Unable to resolve symbol: foo in this context, compiling:(NO_SOURCE_PATH:0)
sandbox3=> (def bar 7)
#'sandbox3/bar
sandbox3=> bar
7
sandbox3/user=> (in-ns 'user)
#
user=> foo
6
user=> bar
CompilerException java.lang.RuntimeException: Unable to resolve symbol: bar in this context, compiling:(NO_SOURCE_PATH:0)
def将在编译时确定将创建Var 的命名空间.然后绑定不起作用(binding引入运行时绑定).
def应仅用于顶级或顶级let表单之类的内容.另一个偏离简单的顶层def,人们应该更加谨慎.例如,在许多方面binding肯定与顶级类似,let并且def将使用预期的线程局部绑定来评估表达式的值部分:
user=> (let [nspace (create-ns (gensym "foo"))]
(binding [*ns* nspace]
(def foo *ns*)))
#'user/foo
user=> foo
#<Namespace foo3>
Run Code Online (Sandbox Code Playgroud)
但是,首先创建Var的方式在执行到达def表单时完全不受运行时状态的影响.
要动态创建Vars,请使用intern- 它是具有完全可预测行为的常规函数.