2009-09-08 49 views
16

在Scala中我可以这样做:斯卡拉覆盖非抽象DEF与VAR

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" 
} 

为什么提供一个默认的定义同样的事情我不能这样做吗?

编辑:经过对中阶用户会话邮件列表,我有raised this in trac

回答

19

在Scala中,当你写一个var foo,Scala编译器会自动生成一个setter(称为foo_=)和吸气剂(称为foo),并将该字段设置为私有(如果反编译具有'公共'Scala字段的类,您将会看到它是私有的“)。这就是'方法foo_ =不重写'错误的意思。在你的特质中,你还没有定义一个foo_=的方法,并且对于公共场的二传手和吸引子,总是成对出现。

如果您没有在特征中提供默认值(即抽象方法),那么override关键字不是必需的。因此,在你的第一个例子中,getter覆盖了抽象方法和setter ......它就在那里。编译器不会抱怨。但是当您提供特征中方法的实际实现时,您需要在覆盖时专门编写override关键字。当编写protected var foo时,您没有为吸气剂指定override关键字,并且在编写override protected var foo时,您还向编译器表明方法foo_=将被覆盖,但该特征没有此类方法。

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

如果你想有类似行为的var你可以做这样的事情(具有明确的setter和getter方法):

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

现在你可以做任何你可以用一个变种:)做。

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

对不起 - 我犯了一个错误 - 原来的特质方法也应该受到保护。我不确定我是否同意你在逻辑上无法用'var'覆盖'def'。我所有的'def'都在说我期望有一个名为'foo'的访问器,它返回一个String - 声明一个'var'就是我实现这个 – 2009-09-08 11:15:56

+0

我想我同意你的看法。当我写出答案时,我一直认为压倒一切是一个更严格的概念。我会编辑答案,并提供一个可行的解决方案:)。 – 2009-09-08 11:52:04

+0

这是一个耻辱,没有'覆盖def as var'语法 – 2009-09-08 12:07:06