为什么Smartcast在nullcheck之后不工作

我试图到来的代码,并希望创建一个类的第10天。我知道值可以为空,所以我宣布他们为空。 在某些时候,我需要检查值是否被赋值,然后用它做些什么。 出现这个问题。 我通过high != null预先检查,但在接下来的行中,我必须使用!! 说服编译器,它实际上是空的。

它似乎找不到适当的compareTo方法,尽管它首先是空检查。 我想,它没有smartcast我的变量

 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-version使用的是1.1.3-2

这是一个错误? 我做错了什么?

high != nullhigh > value另一个线程可能会执行high = null ,使null检查无效。 所以这是预期的行为。

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

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

既然你把var得很high ,那么它是可变的。 即使您在此之前有明确的空检查,也不能保证该变量不为空。

官方解释 :

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

  • val局部变量 – 总是;
  • val属性 – 如果属性是私有的或者内部的,或者在声明属性的相同模块中执行检查。 智能转换不适用于打开属性或具有自定义获取者的属性;
  • var局部变量 – 如果变量在检查和用法之间没有被修改,并且没有在修改它的lambda中被捕获;
  • var属性 – 从不(因为变量可以随时由其他代码修改)。

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

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

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

你可以解决这个问题,如果你声明的财产private

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