Scala使用var覆盖非抽象def

时间:2009-09-08 09:07:41

标签: scala override

在Scala我可以这样做:

trait SomeTrait {
  protected def foo: String
}

class Wibble extends SomeTrait {
  protected var foo = "Hello"
}

但我不能做同样的事情,我提供了foo

的默认定义
trait SomeTrait {
  protected def foo: String = "World"
}

class Wibble extends SomeTrait {
  protected var foo = "Hello" //complains about lack of override modifier

  override protected var foo = "Hello" //complains "method foo_ overrides nothing"
}

为什么我不能这样做?

编辑:在scala-users邮件列表上进行对话后,我有raised this in trac

1 个答案:

答案 0 :(得分:21)

在Scala中,当您编写var foo时,Scala编译器会自动为其生成一个setter(称为foo_=)和一个getter(称为foo),并将该字段设置为private(如果您使用javap反编译具有'公共'Scala字段的类,您将看作私有。这就是'方法foo_ =无所事事'错误意味着什么。在您的特质中,您没有定义foo_=方法,而公共字段设置器和getter 总是成对出现。

如果您没有在特征中提供默认值(即抽象方法),则不需要override关键字。因此,在您的第一个示例中,getter重写了抽象方法和setter ......它就在那里。编译器没有抱怨。但是当您在特征中提供方法的实际实现时,您需要在覆盖时专门编写override关键字。在编写protected var foo时,您没有为getter指定override关键字,在编写override protected var foo时,您还向编译器表明要覆盖方法foo_= ,但特质没有这样的方法。

另外,从逻辑上讲,你不能真正用def覆盖var(考虑严格的覆盖视图,如上一段所述)。 def在逻辑上是一个函数(你给它一些输入,它产生一个输出)。 var类似于无参数函数,但也支持将其值设置为其他函数,这是函数不支持的操作。相反,如果您将其更改为val,则可以。它就像一个总是产生相同(缓存)结果的函数。

如果你想要与var有类似的行为,你可以做这样的事情(通过明确的setter和getter):

class Wibble extends SomeTrait {
  private var bar = "Hello"
  override protected def foo = bar
  protected def foo_=(v: String) { bar = v}
}

现在你可以做任何你可以用var做的事情。)。

val x = new Wibble
println(x.foo) // yields "Hello"
x.foo = "Hello again"
println(x.foo) // yields "Hello again"