Clojure中的Let vs.Binding

Clojure中的Let vs.Binding,binding,clojure,let,Binding,Clojure,Let,我知道它们是不同的,因为一个用于设置*编译路径*,另一个不用于设置。然而,我需要帮助解释为什么它们不同 让使用给定绑定创建一个新的作用域,但是绑定…?绑定将值绑定到每线程全局环境中的名称 正如您所提到的,让为所述绑定创建一个新的作用域。让为某些值创建一个词汇范围的不可变别名绑定为某些Var创建动态范围的绑定 动态绑定意味着绑定表单中的代码以及该代码调用的任何代码(即使不在本地词法范围内)将看到新绑定 鉴于: user> (def ^:dynamic x 0) #'user/x bindi

我知道它们是不同的,因为一个用于设置
*编译路径*
,另一个不用于设置。然而,我需要帮助解释为什么它们不同


使用给定绑定创建一个新的作用域,但是
绑定
…?

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


正如您所提到的,
为所述绑定创建一个新的作用域。

为某些值创建一个词汇范围的不可变别名<代码>绑定为某些
Var
创建动态范围的绑定

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

鉴于:

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
-引入的绑定是不可变的<代码>绑定-引入的绑定是线程本地可变的:

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

另请参见。

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

对于绑定,在将所有初始值绑定到变量之前,将对其进行求值。这与let不同,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

这真的提高了我的理解力。谢谢你,先生!x必须与^:dynamic提示绑定才能不抛出错误,我认为是。您需要^:dynamic将x定义为0(也是动态的),以使第二个示例正常工作。