为什么在nullcheck之后Smartcast无法工作

Tor*_*ist 7 kotlin

我正在尝试代码的出现,并希望在第10天创建一个类.我知道值可以为null,因此我将它们声明为可空.在某些时候,我需要检查值是否已分配并对其执行某些操作.问题来了.我事先检查过high != null,但在接下来的行中,我必须!!用来说服编译器它实际上是null.

它似乎找不到合适的compareTo方法,尽管首先进行了无效检查.我猜,它没有智能播放我的变量

private class Bot(val number: Int, var low: Int?, var high: Int?) {

  fun acceptValue(value: Int) {
    if (low == null && high == null) {
      high = value
    } else {
      if (high != null) {
        if (high!! > value) { //it doesn't compile, because appareantly, high is still not considered nonnull at this point
          low = value
        } else {
          low = high
          high = value
        }
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

kotlin版是用的 1.1.3-2

那是一个错误吗?难道我做错了什么?

Bak*_*aii 6

既然你被定义high为a var,它是可变的.即使在此之前有明确的空检查,也无法保证变量不为null.

官方解释:

请注意,当编译器无法保证变量在检查和使用之间无法更改时,智能强制转换不起作用.更具体地说,智能演员表适用于以下规则:

  • val局部变量 - 总是;
  • val属性 - 如果属性是私有属性或内部属性,或者在声明属性的同一模块中执行检查.智能模型不适用于具有自定义getter的开放属性或属性;
  • var局部变量 - 如果在检查和使用之间没有修改变量,并且没有在修改它的lambda中捕获;
  • var属性 - 从不(因为变量可以在任何时候被其他代码修改).

在你的情况下,你可以使用.let:

high?.let {
    if (it > value) {
        low = value
    } else {
      low = it
      high = value
    }
} ?: run {
    //high == null
}
Run Code Online (Sandbox Code Playgroud)

建议阅读:在Kotlin中,处理可空值,引用或转换它们的惯用方法是什么


Kis*_*kae 3

high != null和之间high > value另一个线程可以这样做high = null,使空检查无效。所以这是预期的行为。

解决这个问题的方法是使用一个不能从外部更改的临时变量:

val cHigh = high
if (cHigh != null) {
    if (cHigh > value) {
        ....
Run Code Online (Sandbox Code Playgroud)