Kotlin称“无法进行智能投射,因为此时属性可能已更改". [英] Kotlin "Smart cast is impossible, because the property could have been changed by this time"
问题描述
为什么我使用2号脚本时Android Studio显示错误. 我发现1和2之间没有区别.
Why Android Studio show error when I use No.2 script. I found no different between 1 and 2.
class Adapter {
var nameList : ArrayList<String>? = null
}
class Program {
private fun send() {
val list: ArrayList<String> = ArrayList()
val adapter = Adapter()
// Case 1
var otherList = adapter.nameList
if (otherList != null) {
list.addAll(otherList) // <--- no error
}
// Case 2
if (adapter.nameList!=null) {
list.addAll(adapter.nameList) // <--- Error here
// Smart cast to 'kotlin.collections.ArrayList<String> /* = java.util.ArrayList<String> */' is impossible, because 'adapter.nameList' is a mutable property that could have been changed by this time
}
}
}
请解释这种情况
推荐答案
IDE应该向您发出警告,解释说在进行空检查之后,adapter.nameList
可能已被另一个线程更改,并且在您调用list.addAll(adapter.nameList)
,adapter.nameList
到那时实际上可能为空(再次,因为另一个线程可能已经更改了该值.这是竞争条件).
The IDE should give you a warning, explaining that after the null check, it's possible that adapter.nameList
was changed by another thread, and that when you call list.addAll(adapter.nameList)
, adapter.nameList
could actually be null by that point (again, because a different thread could have changed the value. This would be a race condition).
您有一些解决方案:
-
将
nameList
设为val
,将其引用为final
.由于它是最终的,因此可以保证另一个线程无法更改它.这可能不适合您的用例.
Make
nameList
aval
, which makes its referencefinal
. Since it's final, it's guaranteed another thread can't change it. This probably doesn't fit your use case.
class Adapter {
val nameList : ArrayList<String>? = null
}
在执行检查之前创建名称列表的本地副本.因为它是本地副本,所以编译器知道另一个线程无法访问它,因此无法对其进行更改.在这种情况下,可以使用var
或val
定义本地副本,但我建议使用val
.
Create a local copy of name list before you do the check. Because it's a local copy, the compiler knows that another thread can't access it, and thus it can't be changed. The local copy could be defined with either a var
or a val
in this case, but I recommend val
.
val nameList = adapter.nameList
if (nameList != null) {
list.addAll(nameList)
}
使用Kotlin提供的一种实用程序功能来解决这种情况. let函数使用内联函数将其调用的引用复制为参数.这意味着它可以有效地编译为与#2相同的代码,但是更加简洁. 我更喜欢这种解决方案.
adapter.nameList?.let { list.addAll(it) }
这篇关于Kotlin称“无法进行智能投射,因为此时属性可能已更改".的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!