Scala使用var覆盖非抽象def

oxb*_*kes 18 overriding scala

在Scala我可以这样做:

trait SomeTrait {
  protected def foo: String
}

class Wibble extends SomeTrait {
  protected var foo = "Hello"
}
Run Code Online (Sandbox Code Playgroud)

但我不能做同样的事情,我提供了默认定义 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"
}
Run Code Online (Sandbox Code Playgroud)

为什么我不能这样做?

编辑:在scala-users邮件列表上进行对话后,我在trac中提出了这个问题

Fla*_*gan 21

在Scala中,当你编写一个时var foo,Scala编译器自动为它生成一个setter(被叫foo_=)和一个getter(被调用foo),并将该字段设置为private(如果你反编译一个有'public'的类,你会看到它是私有的Scala字段与javap).这就是'方法foo_ =无所事事'错误意味着什么.在你的特质中,你还没有定义一个foo_=方法,对于公共字段设置器和getter 总是成对出现.

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

此外,从逻辑上讲,你真的不能重写defvar(考虑覆盖,像前一段的严格的观点).A def在逻辑上是一个函数(你给它一些输入,它产生一个输出).A var类似于无参数函数,但也支持将其值设置为其他函数,这是函数不支持的操作.相反,如果您将其更改为a val,那就没问题.它就像一个总是产生相同(缓存)结果的函数.

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

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

现在你可以用var :)做任何事情.

val x = new Wibble
println(x.foo) // yields "Hello"
x.foo = "Hello again"
println(x.foo) // yields "Hello again"
Run Code Online (Sandbox Code Playgroud)

  • 抱歉 - 我犯了一个错误 - 原始的特征方法也应该受到保护。我不确定我是否同意你关于逻辑上无法用“var”覆盖“def”的观点。我所有的“def”是说,我希望有一个名为“foo”的访问器,它返回一个字符串 - 声明一个“var”是这个的实现 (2认同)