为什么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 != null
和high > 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?) { ... }