这是 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
然后每个表达式依次编译和执行。这意味着在编译表达式 #2 时,表达式 #1 的执行效果是可见的。
变量的动态检查发生在编译时,而不是运行时,因此表达式 #1 的运行意味着表达式 #2 中对 v 的引用将以不同的方式编译,以处理可能的重新绑定的变量。
对于 let 表达式,整个表达式会一次性编译和执行。因此当 #2 编译时,#1 尚未执行,所以变量不会被标记为动态,因此编译器不会生成处理已绑定变量的代码。