这就是 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 的引用将以不同的方式编译来处理可能被 rebound 的变量。
对于 let 表达式,整个表达式都会一次性编译然后执行。因此,当 #2 被编译时,#1 还未执行,所以变量不会被标记为动态的,因此编译器不会发出处理 bound 变量的代码。