我知道它们是不同的,因为一个用于设置*compile-path*
而一个不用。但是,我需要帮助解决他们与众不同的原因。
let
使用给定的绑定创建一个新范围,但是binding
...?
答案 0 :(得分:106)
let
为某个值创建一个词法范围的不可变别名。 binding
为某些Var
创建动态范围的绑定。
动态绑定意味着binding
表单中的代码和代码调用的任何代码(即使不在本地词法范围内)都会看到新的绑定。
假设:
user> (def ^:dynamic x 0)
#'user/x
binding
实际上为Var
创建动态绑定,但let
仅使用本地别名隐藏var:
user> (binding [x 1] (var-get #'x))
1
user> (let [x 1] (var-get #'x))
0
binding
可以使用限定名称(因为它在Var
s上运行)而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
答案 1 :(得分:12)
let vs 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
答案 2 :(得分:9)
binding
将值绑定到每线程全局环境中的名称
正如您所提到的,let
为所述绑定创建了一个新范围。