inheritance - 错误或功能 : Kotlin allows to change 'val' to 'var' in inheritance

标签 inheritance side-effects kotlin

我刚刚开始探索 Kotlin 语言。我正在为继承、var&val 和副作用而苦苦挣扎。

如果我用 val x 声明一个特征 A 并在 AImpl 中覆盖 x ,则可以将其覆盖为 var(参见下面的代码)。令人惊讶的是, A 中的 print() 方法会受到 x 重新分配的影响,即使 xA。这是错误还是功能?

代码:

trait A {
  fun print() {
    println("A.x = $x")
  }

  val x : Int;
}

class AImpl(x : Int) : A {
  override var x = x; // seems like x can be overriden as `var`
}

fun main(args: Array<String>) {

  val a = AImpl(2)

  a.print() // A.x = 2

  a.x = 3; // x can be changed

  // even though print() is defined in trait A
  // where x is val it prints x = 3
  a.print() // A.x = 3

}

我知道如果我明确定义 a 类型为 A 则不允许更改 x:

val a = AImpl(2) : A
a.x = 3 // ERROR: value x cannot be reassigned

但正如第一种情况所示,继承可能会导致副作用,这在 A 中显然不是有意的。如何保护值不被继承更改?

最佳答案

您可以使您的 val final,即完全禁止覆盖它。 如果你在一个类中定义了一个val,它默认是final

另外,如果你需要用 var 覆盖 val,但不希望 setter 公开,你可以这样说:

override var x = 1
    private set

var 覆盖 val 是一项功能。这相当于添加了一个 set-method,而在父类(super class)中只有一个 get-method。这对于实现一些模式(例如只读接口(interface))相当重要。

除了将其设为 final 之外,没有办法“保护”你的 val 不被覆盖,因为 val > 并不意味着“不可变引用”,而仅仅是“只读属性”。换句话说,当你的 trait A 声明一个 val 时,这意味着 通过一个 A 类型的引用客户端无法编写此 val,没有其他保证,或者确实可能。

附:分号在 Kotlin 中是可选的,可以完全省略它们

关于inheritance - 错误或功能 : Kotlin allows to change 'val' to 'var' in inheritance,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22820505/

相关文章:

android - 如何获取特定路径下的所有文件列表

c++ - 不直接继承的覆盖方法实现注入(inject)

C#继承问题

functional-programming - D中的纯函数式编程

functional-programming - 为什么引发异常是副作用?

java - HashMap在Kotlin中是如何实现MutableMap接口(interface)的?

oop - 在 MATLAB 中覆盖父类(super class)方法和访问修饰符

c++ - 抽象基类实现

memory - 更糟糕的罪过 : side effects or passing massive objects?

multiple-inheritance - Kotlin中的多重继承