值影响后不可能智能转换为“布尔值”

Z3n*_*3nk 4 null boolean thread-safety optional kotlin

第二个 println 错误:

智能转换为 'Boolean' 是不可能的,因为 'r.isSquare' 是一个可变属性,此时可能已更改

fun main(args: Array<String>) {
    val r: Rectangle = Rectangle(5,5)
    println(r.isSquare)
    r.isSquare = true
    println(r.isSquare) // error but works with println(r.isSquare?:false)

}

data class Rectangle(var height: Int, var width: Int){
    var isSquare: Boolean? = null
}
Run Code Online (Sandbox Code Playgroud)

如果它是空的,它会像第一个 println 一样打印空,为什么我必须这样做?

编辑 2

感谢您的所有回答,我现在明白:第一个 println 是

println(message: Any?)
Run Code Online (Sandbox Code Playgroud)

第二个 println 是

println(message: Boolean)
Run Code Online (Sandbox Code Playgroud)

因为 r.isSquare = true 使编译器相信 isSquare 是布尔值而不是布尔值?

编辑2

这是我如何处理编译器以保持信任 isSquare 是布尔值?

fun main(args: Array<String>) {
    val r: Rectangle = Rectangle(5, 5)
    println(r.isSquare)
    r.isSquare = true as Boolean? // if no cast, he will try wrong println signature
    println(r.isSquare)
}

data class Rectangle(var height: Int, var width: Int){
    var isSquare: Boolean? = null
}
Run Code Online (Sandbox Code Playgroud)

Bob*_*Bob 5

由于r.isSquare是可变属性,编译器无法在空检查后将其智能转换为非空属性。

您可以使用let

r.isSquare.let { println(it) }
Run Code Online (Sandbox Code Playgroud)

let只读取r.isSquare一次的值,它提供与itlambda 内部相同的值。因此,即使在空检查之后,您也不必使用?!!访问布尔值。

来自Kotlin 规范

该语言使用有关前面的 null 检查、类型检查 (is, !is)、安全调用运算符 (?.) 和 Nothing-returning 表达式的信息来推断有关变量类型的其他信息(除了显式指定或从初始化程序推断的)他们的声明)在某些块甚至表达式中可能更具体。然后使用此信息来启用对这些表达式的更广泛的操作集并选择更具体的重载。

fun main(args: Array<String>) {
    var x : Any
    x = ""
    x.toUpperCase() // OK, smart cast to String
}
Run Code Online (Sandbox Code Playgroud)

第一个println使用这个println(message: Any?)

由于您正在分配trueisSquare下一个,当您尝试打印isSquareBoolean类型时,编译器会尝试将其智能转换为该类型。但它不能智能转换,因为该属性是可变类型。

如果删除该行, r.isSquare = true,则编译器不会尝试将其智能转换为Boolean并使用printlnwithAny?作为参数。