此代碼無法編譯。
class MyClass {
var w: String? = "Hello"
init {
if(w!=null) {
println(w.length)
}
}
}
編譯器錯誤:智能轉換為 'String' 是不可能的,因為 'w' 是一個可變屬性,此時可能已更改。這是什么意思?類似的代碼可以完美編譯。
fun main(args: Array<String>) {
var w: String? = "Hello"
if(w!=null) {
println(w.length)
}
}
它們是相似的,因為根據我的理解,在這兩種情況下,變數w都將被實體化,if塊將在它之后立即運行。那么為什么這段代碼可以完美編譯呢?
uj5u.com熱心網友回復:
一般來說,這些錯誤是因為編譯器不能保證變數不能在空檢查和假設它不為空的用法之間改變。在大多數情況下,這是因為另一個執行緒可以同時修改變數。
例如,另一個init塊中可能有一些代碼產生一個執行緒,可以改變變數的值:
class MyClass {
var w: String? = "Hello"
init {
thread {
w = null
}
}
init {
if (w!=null) {
println(w.length)
}
}
}
編譯器不會檢查所有可能產生類似影響的代碼,因此它更傾向于保守并給您一個錯誤。
在main方法的情況下,變數是區域的,所以編譯器可以更容易地保證它不能被其他任何東西改變。
要解決此問題,您可以在訪問w屬性時創建一個中間區域變數:
val myW = w
if (myW != null) {
println(myW.length)
}
或使用let:
w?.let { nonNullW ->
println(nonNullW.length)
}
uj5u.com熱心網友回復:
在您的第一個代碼塊中,w是一個屬性。在您的第二個代碼塊中,w是一個區域變數。
可變屬性不能被智能轉換,因為編譯器不能確保屬性的值在檢查型別/可空性和使用值之間不會改變。
當需要使用可空屬性時,為了避免進行非空斷言,必須先將其復制到區域變數中。您可以顯式執行此操作,也可以使用作用域函式執行此操作。
//Explicit
val localW = w
if (localW != null) {
println(localW.length)
}
// The common ?.let pattern
w?.let { println(it.length) }
// run with function reference
w?.length?.run(::println)
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/324542.html
