假设我有一个Kotlin类Dog
,它有两个属性weight
和weightInKgs
class Dog(val weight: Double) {
// property without initializing works. Why?
val weightinKgs: Double
get() = weight/ 2.2;
}
上面的代码运行时没有出现错误。我知道Kotlin中的每个属性都必须初始化,那么为什么在不初始化属性的情况下定义getter有效呢?其次,当val
被weightInKgs
更改为var
时,它会产生一个要求初始化的错误。将其更改为var
是如何破坏代码的?
class Dog(val weight: Double) {
// well its doesn't work now.
var weightinKgs: Double
get() = weight/ 2.2;
}
必须初始化带有支持字段的每个属性。如果以下任何一项为真,则属性有一个后备字段:
- 使用
=
在声明站点初始化backing字段 - 它有一个引用
field
的自定义getter或setter - 它使用隐式getter或setter,后者隐式使用
field
否则,它没有后备字段。
如果getter和/或setter没有使用后备字段,就不需要初始化一个。您的第一个代码块有一个不使用field
的自定义getter。
在第二个代码块中,您有一个var
,它使用的是隐式setter,它使用了backing字段,因此必须初始化backing字段。
如果不明显的话,get()
是一个函数,每次调用它都会计算一个值(weight / 2.2
(。它基本上等同于这个
fun getWeightInKgs(): Double {
return weight / 2.2
}
所以这就是为什么它没有一个支持字段,它实际上并没有存储一个值。但是Kotlin将这些类型的getX()
函数(以及set
、is
等(表示为属性,并鼓励您使用属性访问语法,因此dog.weightInKgs
而不是dog.getWeightInKgs()
。有点隐藏的具体实现细节
如果你不想每次都计算重量,只想做一次,那么你只需要做
val weightInKgs = weight / 2.2
然后它将有一个后备字段,因为该值必须存储在某个地方。您也可以有一个getter函数,它引用私有val
或var
并返回其值,而不是为属性本身提供一个支持字段,但如果您需要做这种事情,您可能会理解为什么要这样做!这通常适用于当您的getter和/或setter正在做比隐藏或验证内部数据值更复杂的事情时