我刚刚开始探索 Kotlin 语言。我正在为继承、var&val 和副作用而苦苦挣扎。
如果我用 val x
声明一个特征 A
并在 AImpl
中覆盖 x
,则可以将其覆盖为 var
(参见下面的代码)。令人惊讶的是, A
中的 print()
方法会受到 x
重新分配的影响,即使 x
是A
。这是错误还是功能?
代码:
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/