我知道它们是不同的,因为一个用于设置*compile-path*
,一个不用.但是,我需要帮助他们为什么不同.
let
使用给定的绑定创建一个新的范围,但是binding
......?
let
为某个值创建一个词法范围的不可变别名. binding
为某些人创建动态范围的绑定Var
.
动态绑定意味着binding
表单中的代码和代码调用的任何代码(即使不在本地词法范围内)将看到新的绑定.
鉴于:
user> (def ^:dynamic x 0) #'user/x
binding
实际上为a创建一个动态绑定,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
另见Vars,让.
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
binding
将值绑定到每线程全局环境中的名称
如您所述,let
为所述绑定创建一个新范围.