Почему Smartcast не работает после nullcheck

Я пытаюсь приступить к коду и хотел создать класс на 10-й день. Я знаю, что значения могут быть нулевыми, поэтому я объявил их нулевыми. В какой-то момент мне нужно проверить, назначено ли значение и что-то сделать с ним. Наступает проблема. Я проверяю заранее через high != 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 } } } } } 

версия kotlin – это 1.1.3-2

Это ошибка? Я делаю что-то неправильно?

Между значением high != null и high > value другой поток может делать high = null , что делает недействительным нулевую проверку. Так что это ожидаемое поведение.

Способ решения этой проблемы – использовать временную переменную, которая не может быть изменена извне:

 val cHigh = high if (cHigh != null) { if (cHigh > value) { .... 

Поскольку вы игнорируете high как var , он изменен. Вы не можете гарантировать, что переменная не является нулевой, даже если у вас есть явная проверка null перед этим.

Официальное объяснение :

Обратите внимание: умные приведения не работают, когда компилятор не может гарантировать, что переменная не может измениться между проверкой и использованием. Более конкретно, интеллектуальные отладки применимы в соответствии со следующими правилами:

  • val локальные переменные – всегда;
  • свойства val – если свойство является частным или внутренним, или проверка выполняется в том же модуле, где объявлено свойство. Смарт-броски неприменимы к открытым свойствам или свойствам, которые имеют пользовательские геттеры;
  • var local variables – если переменная не изменяется между проверкой и использованием и не записывается в лямбда, которая ее модифицирует;
  • var properties – never (потому что переменная может быть изменена в любой момент другим кодом).

В этом случае вы можете использовать .let :

 high?.let { if (it > value) { low = value } else { low = it high = value } } ?: run { //high == null } 

Предлагаемое чтение: В Котлине, какой идиоматический способ справиться с нулевыми значениями, ссылаясь или преобразуя их

Вы можете решить эту проблему, если вы объявите privatetiries private :

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