这是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尚未执行,因此变量不会被标记为动态的,所以编译器不会发出处理已绑定变量的代码。