了解var和val对属性的getter和setter的影响



假设我有一个Kotlin类Dog,它有两个属性weightweightInKgs

class Dog(val weight: Double) {  
    // property without initializing works. Why?
    val weightinKgs: Double
    get() = weight/ 2.2;
}

上面的代码运行时没有出现错误。我知道Kotlin中的每个属性都必须初始化,那么为什么在不初始化属性的情况下定义getter有效呢?其次,当valweightInKgs更改为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()函数(以及setis等(表示为属性,并鼓励您使用属性访问语法,因此dog.weightInKgs而不是dog.getWeightInKgs()。有点隐藏的具体实现细节

如果你不想每次都计算重量,只想做一次,那么你只需要做

val weightInKgs = weight / 2.2

然后它有一个后备字段,因为该值必须存储在某个地方。您也可以有一个getter函数,它引用私有valvar并返回其值,而不是为属性本身提供一个支持字段,但如果您需要做这种事情,您可能会理解为什么要这样做!这通常适用于当您的getter和/或setter正在做比隐藏或验证内部数据值更复杂的事情时

最新更新