第二个打印错误:
智能投射到"布尔值"是不可能的,因为"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
}
如果它是空的,它会像第一个 println 一样打印空,为什么我必须这样做?
编辑 2
感谢您的所有回答,我现在明白了: 第一个打印是
println(message: Any?)
第二个打印是
println(message: Boolean)
因为 r.isSquare = true 使编译器信任 isSquare 是布尔值而不是布尔值?
编辑2
以下是我如何处理编译器以保持信任是方形是布尔值吗?
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
}
由于r.isSquare
是可变属性,因此编译器无法在 null 检查后将其智能强制转换为非 null 属性。
您可以使用let
:
r.isSquare.let { println(it) }
let
只读取一次r.isSquare
的值,它提供的值与 lambda 中的it
值相同。因此,即使在 null 检查之后,您也不必使用?
或!!
来访问布尔值。
来自 Kotlin 规范:
该语言使用有关前面检查 null、检查的信息 对于类型(is,!is(,安全呼叫操作员(?.(和无返回 用于推断有关变量类型的其他信息的表达式 (超出从初始值设定项显式指定或推断的 他们的声明(在某些区块中可能更具体,或者 甚至表情。然后,此信息将用于启用更广泛的 对这些表达式进行操作,并选择更具体的重载。
fun main(args: Array<String>) { var x : Any x = "" x.toUpperCase() // OK, smart cast to String }
第一个println
使用此println(message: Any?)
由于接下来要true
分配给isSquare
,因此当您尝试打印isSquare
类型时,编译器会尝试将智能转换为Boolean
类型。但它无法智能转换,因为该属性是可变类型。
如果删除行r.isSquare = true
,则编译器不会尝试将其智能转换为Boolean
,而是使用带有Any?
的println
作为参数。
为了使它工作,您必须在变量后添加一个非空断言调用 (!!(。要么 r!.是方形或r.is广场!!
fun main(args: Array<String>) {
val r: Rectangle = Rectangle(5,5)
println(r.isSquare)
r.isSquare = true println(r.!! isSquare)
}
data class Rectangle(var height: Int, var width: Int) {
var isSquare: Boolean? = null
}
As isSquare 是一个可变属性 (var(。这意味着在行之间,您在哪里写入值然后读取它,另一个线程可以修改它并因此获得 NPE。
r.isSquare = true
//Another thread set r.isSquare = null
println(r.isSquare) // you get a null pointer exception
每次使用可为空的变量时,都必须检查属性可空性。
因为 Android 中的 println(( 函数不支持布尔?,而布尔? 在 Kotlin 中具有可变属性,无法通过 Kotlin 的智能强制转换自动解包。
尝试 String? 或 Int? 或任何具有可变和可为空属性的类型都会发生同样的事情。