为什么不能在scala中覆盖可变变量?

时间:2015-07-14 05:31:31

标签: scala inheritance override

为什么不能在scala中覆盖可变变量?

class Abs(var name: String){
}

class AbsImpl(override var name: String) extends Abs(name){
}

上面的代码给出了以下编译时错误: -

variable name cannot override a mutable variable

如果name声明为val,则上面的代码可以正常工作。

5 个答案:

答案 0 :(得分:4)

如果您可以使用var覆盖var,则覆盖成员可以具有更窄的类型。 (这就是如何定义覆盖。)

然后你可以指定一个更宽类型的值,然后读取它,期望更窄的类型,然后失败。

所涉及的二传手的插图:

scala> class A ; class B extends A
defined class A
defined class B

scala> abstract class C { var x: A } ; class D extends C { var x: B = _ }
<console>:13: error: class D needs to be abstract, since variable x in class C of type A is not defined
(Note that an abstract var requires a setter in addition to the getter)
       abstract class C { var x: A } ; class D extends C { var x: B = _ }
                                             ^

scala> abstract class C { var x: A }
defined class C

scala> class D extends C { var x: B = _ ; def x_=(a: A) = ??? }
defined class D

答案 1 :(得分:3)

简短回答:您需要将-Yoverride-vars传递给Scala编译器。

根据规范,var既是getter又是setter,正常的覆盖规则适用于这些方法。然而,这被证明会产生一些不良后果w.r.t.到final关键字和内联。编译器中的代码提到了一些需要澄清的规范:

// TODO: this is not covered by the spec. We need to resolve this either by changing the spec or removing the test here.
if (!settings.overrideVars)
  overrideError("cannot override a mutable variable")

相关票证:SI-3770

答案 2 :(得分:1)

我认为目的只是设置继承的var name的值。这可以通过这种方式实现(没有override var):

class Abs(var name: String){
}

class AbsImpl(name: String) extends Abs(name){
}

歧义来自于name: String中的本地变量AbsImpl,该变量以var name: String中的继承Abs命名。类似的代码,语法不明确,但也不那么优雅:

class Abs(var name: String){
}

class AbsImpl(name_value: String) extends Abs(name_value){
}

答案 3 :(得分:1)

当你想要覆盖一个var,它等同于尝试覆盖java中不可能的字段。

答案 4 :(得分:0)

当您尝试覆盖的var已经有作业时会发生这种情况。我不确定为什么这是禁止的,但它也没什么意义。

另见this question

name定义为抽象而非

trait Abs {
  var name: String
}

class AbsImpl(name0: String) extends Abs {
  var name = name0
}

trait Abs {
  var name: String
}

class AbsImpl(private var name0: String) extends Abs {
  def name = {
    println("getter")
    name0
  }

  def name_=(value: String) = {
    println("setter")
    name0 = value
  }
}