【问题标题】:Bug or Feature: Kotlin allows to change 'val' to 'var' in inheritance错误或功能:Kotlin 允许在继承中将 'val' 更改为 'var'
【发布时间】:2014-05-14 06:29:43
【问题描述】:

我刚刚开始探索 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 中显然不打算出现的副作用。如何保护值不被继承更改?

【问题讨论】:

    标签: inheritance side-effects kotlin


    【解决方案1】:

    你可以让你的valfinal,即完全禁止覆盖它。 如果在类中定义val,默认为final

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

    override var x = 1
        private set
    

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

    没有办法“保护”您的val 不被以允许更改突变的方式覆盖,而不是使其成为final,因为val 并不意味着“不可变引用”,而仅仅是“只读”财产”。换句话说,当你的 trait A 声明一个 val 时,这意味着通过A 类型的引用客户端不能写这个val,没有其他保证,或者确实有可能。

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

    【讨论】:

      【解决方案2】:

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

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

      在这个例子中,可见性限制也被一个子类放宽了,尽管有些人认为这种技术是一种反模式。

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

      在 kotlin 中,您可以使用 open 修饰符显式定义任何特定的类成员是否可以被子类覆盖。然而,在特征中,默认情况下所有成员都是打开的。解决方案是用类替换 trait,这样你就可以控制继承:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-03-23
        • 2018-11-13
        • 1970-01-01
        • 1970-01-01
        • 2023-03-21
        • 2015-04-11
        相关资源
        最近更新 更多