19

在 Clojure 中,

(def x 3)
(eval '(prn x))

打印 3,而

(let [y 3]
   (eval '(prn y)))

(binding [z 3] (eval '(prn z)))

生成“无法解析 var”异常。

根据http://clojure.org/evaluationevalload-string等生成临时命名空间来评估其内容。因此,我希望上述代码示例都不起作用,因为(def x 3)是在我当前的命名空间中完成的,而不是由eval.

  1. 为什么第一个代码示例有效,而后两个无效?
  2. 如何eval不使用绑定变量的表单def

谢谢!

4

1 回答 1

16

1.:

这不起作用的原因(或多或少)在您链接的页面上给出:

It is an error if there is no global var named by the symbol […]

和:

[…]

  1. 在当前命名空间中进行查找以查看是否存在从符号到 var 的映射。如果是这样,则该值是该符号所引用的 var 的绑定值。

  2. 这是一个错误。

eval在空(CL-lingo中的null )词法环境中计算表单。这意味着,您不能从调用者的范围内访问词法变量绑定。此外,binding为现有的变量创建新的绑定,这就是为什么你不能“单独”使用它,而不需要declared 或defed 你尝试绑定的变量。此外,词法变量(至少在 CL 中,但如果 Clojure 不是这种情况,我会感到惊讶)在运行时已经不复存在——它们被转换为地址或值。

另请参阅我关于此主题的旧帖子。

2.:

所以,你必须使用动态变量。您可以避免使用显式def,但至少仍然需要declare它们(def没有绑定的 var 名称):

user=> (declare ^:dynamic x)
#'user/x
user=> (binding [x 10] (eval '(prn x)))
10
nil

顺便说一句:我想您知道为什么需要 eval,并且当其他解决方案合适时,它的使用被认为是邪恶的。

于 2011-06-03T00:22:36.560 回答