当前位置: 首页 > 知识库问答 >
问题:

编译错误:智能强制转换为“< type >”是不可能的,因为“< variable >”是由变化的闭包捕获的局部变量

苏昂雄
2023-03-14

为了简化我的真实用例,让我们假设我想在一个列表中找到最大的数字:

var max : Int? = null
listOf(1, 2, 3).forEach {
    if (max == null || it > max) {
        max = it
    }
}

但是,编译失败并出现以下错误:

智能强制转换为“Int”是不可能的,因为“max”是一个由变化的闭包捕获的局部变量

为什么更改的闭包会阻止智能强制转换在此示例中起作用?

共有3个答案

邢烨烨
2023-03-14

在我看来,这像是一个编译器错误。

如果foreach中的内联lambda参数被标记为交叉线,那么我预计会出现编译错误,因为可能会并发调用lambda表达式。

请考虑以下foreach实现:

inline fun <T> Iterable<T>.forEach(crossinline action: (T) -> Unit): Unit {
    val executorService: ExecutorService = ForkJoinPool.commonPool()
    val futures = map { element -> executorService.submit { action(element) } }
    futures.forEach { future -> future.get() }
}

如果没有交叉线修饰符,上述实现将无法编译。没有它,lambda 可能包含非本地回报,这意味着它不能以并发方式使用。

我建议创建一个问题:科特林(KT)|搜狐.

郑宇
2023-03-14

感谢伊利亚对问题的详细解释!您可以使用标准的<code>for(列表中的项){…}</code>表达式,如下所示:

var max : Int? = null
val list = listOf(1, 2, 3)
for(item in list){
    if (max == null || item > max) {
        max = item
    }
}
吴经略
2023-03-14

一般来说,当可变变量在lambda函数闭包中被捕获时,无论是在lambda内部还是在lambda创建后的声明范围内,智能强制转换都不适用于该变量。

这是因为函数可能会脱离其封闭范围,并可能在以后的不同上下文中执行,可能是多次执行,也可能是并行执行。例如,考虑一个假设的函数< code>List.forEachInParallel {...},它对列表中的每个元素执行给定的lambda函数,但是是并行的。

编译器必须生成即使在这种严重情况下也能保持正确的代码,所以它不会假设变量的值在空检查后保持不变,因此不能对其进行智能转换。

但是,<code>是一个列表。forEach非常不同,因为它是一个<code>内联

它可以,但目前,它没有。仅仅因为该功能尚未实现。它有一个悬而未决的问题:KT-7186。

 类似资料: