72

我知道它们是不同的,因为一个用于设置*compile-path*,一个不用于设置。但是,我需要帮助他们为什么不同。

let使用给定的绑定创建一个新范围,但是binding...?

4

3 回答 3

111

let为某个值创建一个词法范围的不可变别名。 binding为 some 创建一个动态范围的绑定Var

动态绑定意味着binding表单内的代码和该代码调用的任何代码(即使不在本地词法范围内)都将看到新的绑定。

鉴于:

user> (def ^:dynamic x 0)
#'user/x

binding实际上为 a 创建了一个动态绑定,Varlet仅使用本地别名隐藏 var:

user> (binding [x 1] (var-get #'x))
1
user> (let [x 1] (var-get #'x))
0

binding可以使用限定名称(因为它在Vars 上运行)并且let不能:

user> (binding [user/x 1] (var-get #'x))
1
user> (let [user/x 1] (var-get #'x))
; Evaluation aborted.
;; Can't let qualified name: user/x

let- 引入的绑定是不可变的。 binding- 引入的绑定是线程局部可变的:

user> (binding [x 1] (set! x 2) x)
2
user> (let [x 1] (set! x 2) x)
; Evaluation aborted.
;; Invalid assignment target

词法与动态绑定:

user> (defn foo [] (println x))
#'user/foo
user> (binding [x 1] (foo))
1
nil
user> (let [x 1] (foo))
0
nil

另请参见Vars

于 2009-10-06T03:00:49.950 回答
13

let 与 binding 的另一个语法差异:

对于绑定,所有初始值都在它们中的任何一个绑定到变量之前进行评估。这与 let 不同,您可以在后续定义中使用先前“别名”的值。

user=>(let [x 1 y (+ x 1)] (println y))
2
nil

user=>(def y 0)
user=>(binding [x 1 y (+ x 1)] (println y))
1
nil
于 2010-11-11T01:44:39.390 回答
9

binding将值绑定到每个线程全局环境中的名称

正如您所提到的,let为所述绑定创建了一个新范围。

于 2009-10-06T02:16:03.347 回答