可空变量的Kotlin Smart Cast

Max*_*xim 3 kotlin

当我尝试创建以下代码时:

class SmartCast {
    var array: MutableList<Int>? = null

    fun processArray() {
        if (array != null && !array.isEmpty()) {
            // process
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

显示此错误:

无法智能地强制将其强制转换为“ MutableList”,因为“数组”是一个可变属性,到那时可能已经更改了

显然,在多线程的情况下,array可以将变量更改为null。但是,如果使用@Synchronized批注,则无法在array != null和之间对变量进行突变!array.isEmpty()

@Synchronized
fun processArray() {
Run Code Online (Sandbox Code Playgroud)

我想知道为什么编译器不允许在同步块中进行智能转换,或者也许可以指定我的应用程序仅设计用于单线程模式?

更新:根据答案,我以以下方式更改了代码:

fun processArray() {
    array?.takeUnless { it.isEmpty() }?.also {
        for (elem in it)
            // process elements
    }
}
Run Code Online (Sandbox Code Playgroud)

JB *_*zet 6

将列表保存到本地变量,然后使用该本地变量。做到这一点的一种优雅方法是使用该let函数,并将其与null安全运算符组合:

array?.let { 
    if (!it.isEmpty()) {
        // process it
    }
}
Run Code Online (Sandbox Code Playgroud)

这在入门指南 BTW 的成语部分中进行了描述。


Ale*_*nov 5

为什么编译器不允许在同步块中进行智能转换

因为这

但是如果我使用@Synchronized 注释,则无法在数组 != null 和 !array.isEmpty() 之间改变变量。

是错的。@Synchronized意味着这个方法不能同时被两个线程调用,但是另一个可以访问同一个实例的线程完全可以自由地重新分配array

您还需要将 setter 标记为@Synchronized,在这种情况下,目前确实无法更改。但是试图弄清楚智能转换什么时候是安全的会导致非常复杂的规则,一种方法的微小变化会突然破坏其他方法的智能转换。所以规则是保守的。