为什么 if not null 不适用于可变变量?
Why does if not null not work for mutable variables?
此代码无法编译。
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
块将紧随其后 运行。那么为什么这段代码可以完美编译?
在您的第一个代码块中,w
是一个 属性。在您的第二个代码块中,w
是一个局部变量。
可变 属性 不能智能转换,因为编译器无法确保 属性 的值在检查 type/nullability 和使用该值之间不会发生变化。
当你需要使用一个可空的属性时,为了避免做非空断言,你必须先将它复制到一个局部变量。您可以明确地或使用范围函数来执行此操作。
//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)
一般来说,这些错误是因为编译器不能保证变量在 null 检查和假定它不为 null 的用法之间不能更改。在大多数情况下,这是因为另一个线程可以同时修改变量。
例如,另一个 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)
}
此代码无法编译。
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
块将紧随其后 运行。那么为什么这段代码可以完美编译?
在您的第一个代码块中,w
是一个 属性。在您的第二个代码块中,w
是一个局部变量。
可变 属性 不能智能转换,因为编译器无法确保 属性 的值在检查 type/nullability 和使用该值之间不会发生变化。
当你需要使用一个可空的属性时,为了避免做非空断言,你必须先将它复制到一个局部变量。您可以明确地或使用范围函数来执行此操作。
//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)
一般来说,这些错误是因为编译器不能保证变量在 null 检查和假定它不为 null 的用法之间不能更改。在大多数情况下,这是因为另一个线程可以同时修改变量。
例如,另一个 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)
}