通常,当在 lambda 函数闭包中捕获可变变量时,智能转换不适用于该变量,无论是在 lambda 内部还是在 lambda 创建后的声明范围内。
这是因为该函数可能会脱离其封闭范围,并可能稍后在不同的上下文中执行,可能多次执行,也可能并行执行。作为一个例子,考虑一个假设的函数 List.forEachInParallel { ... },它为列表的每个元素执行给定的 lambda 函数,但是是并行的。
编译器必须生成即使在这种严重情况下也保持正确的代码,因此它不会假设变量的值在空检查后保持不变,因此不能智能转换它。
但是,List.forEach 完全不同,因为它是一个内联函数。内联函数的主体及其函数参数的主体(除非参数具有 noinline 或 crossinline 修饰符)在调用站点内联,因此编译器可以推断作为参数传递给内联函数的 lambda 中的代码,就好像它直接写在调用方法体中,使智能转换成为可能。
可以,但目前还不行。仅仅是因为该功能尚未实现。它有一个未解决的问题:KT-7186。
分享
改进这个答案
跟随
于 2020 年 7 月 17 日 23:27 编辑
35
+50
In general, when a mutable variable is captured in a lambda function closure, smart casts are not applicable to that variable, both inside the lambda and in the declaring scope after the lambda was created.
It's because the function may escape from its enclosing scope and may be executed later in a different context, possibly multiple times and possibly in parallel. As an example, consider a hypothetical function List.forEachInParallel { ... }
, which executes the given lambda function for each element of the list, but in parallel.
The compiler must generate code that will remain correct even in that severe case, so it doesn't make an assumption that the value of variable remains unchanged after the null check and thus cannot smart cast it.
However, List.forEach
is quite different, because it is an inline function. The body of an inline function and the bodies of its functional parameters (unless the parameter has noinline
or crossinline
modifiers) are inlined at the call site, so the compiler could reason about the code in a lambda passed as an argument to inline function as if it was written directly in the calling method body making the smart cast possible.
It could, but currently, it doesn't. Simply because that feature is not implemented yet. There is an open issue for it: KT-7186.
Follow