这是 let 和 do 之间的区别:对于顶层 do 表达式形式,主体被提升并进行编译和逐个执行。
所以对于
(do
(.setDynamic #'v true) ;1
(binding [v :new] ;2
(println v))
(.setDynamic #'v false) ; 3
)
表达式被分解为三个表达式
(.setDynamic #'v true) ; 1
.
(binding [v :new] ; 2
(println v))
.
(.setDynamic #'v false) ;3
然后每个表达式依次编译和执行。这意味着执行表达式 #1 的影响在编译表达式 #2 时是可见的。
动态检查变量发生在编译时而不是运行时,所以表达式 #1 的运行意味着表达式 #2 中对 v 的引用的编译方式不同,以处理可能的重绑定变量。
对于 let 表达式,整个表达式会一次编译然后执行。所以当 #2 进行编译时,#1 还未被执行,因此变量不会被标记为动态,所以编译器不会发出处理绑定变量的代码。