错误或功能:Kotlin允许在继承中将“val”更改为“var”

我刚开始探索Kotlin语言。 我正在努力继承,var和val和副作用。

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

码:

 trait A { fun print() { println("Ax = $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() // Ax = 2 ax = 3; // x can be changed // even though print() is defined in trait A // where x is val it prints x = 3 a.print() // Ax = 3 } 

我意识到这样一个事实,即如果我明确定义a类型A ,不允许更改x

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

但是,正如第一个案例所显示的那样,继承可能导致副作用,这在A中显然不是有意A 。 如何保护值不被继承改变?

你可以让你的val final ,即禁止压倒一切。 如果你在一个类中定义了一个val ,那么默认是final的。

另外,如果你需要用一个var覆盖val ,但是不想让setter公开,你可以这样说:

 override var x = 1 private set 

var覆盖val 是一个特性 。 这相当于添加一个set方法,而在超类中只有一个get方法。 这在实现一些模式(如只读接口)时非常重要。

没有办法“保护”你的val不被重写,而是允许改变变化,而不是final ,因为val并不意味着“不变的参考”,而只是“只读属性”。 换句话说,当你的特质A声明一个val ,这意味着通过类型A引用客户不能写这个val ,没有其他的保证是有意的,或者确实是可能的。

PS分号在Kotlin中是可选的,完全可以忽略它们

我会认为这是一个功能,因为更改VAL到VAR施加较弱的使用限制, 并且不能破坏任何超类代码 。 可见性修改器可以观察到类似的情况:

 trait A { protected fun print() { ... } } class AImpl: A { public override fun print() { ... } } 

在这个例子中,可见性限制也被一个子类放宽,尽管有些人正在把这个技术看作一个反模式。

如何保护值不被继承改变?

在kotlin中,你可以明确地定义是否任何特定的类成员可以被使用open修饰符的子类覆盖。 然而,在特征上,所有成员都是默认开放的。 解决的办法是用类替换特质,所以你可以控制继承:

 abstract class A { fun print() { ... } val x : Int = 2; } class AImpl(x : Int) : A() { override var x = x // compilation error }