在Scala中选择继承通用方法的特质

3
假设我创建了一个类,混合了两个 trait,这两个 trait 都实现了一个共同的方法,例如下面所示:
abstract class Base {
    var x:Int
    def adder:Int
}

trait One extends Base {
    def adder() = {x+=2; x}
}

trait Two extends Base {
    def adder() = {x+=3; x}
}

class WhichOne(var x:Int = 10) extends Base with One with Two

println((new WhichOne()).adder())

在运行时,Scala当然会抱怨,因为它不知道应该选择哪个trait:

$ scala MixUpTraitImplems.scala 
MixUpTraitImplems.scala:18: error: class WhichOne inherits conflicting members:
  method adder in trait One of type ()Int  and
  method adder in trait Two of type ()Int
(Note: this can be resolved by declaring an override in class WhichOne.)
class WhichOne(val x:Int = 10) extends Base with One with Two
      ^

当然,覆盖 adder() 意味着我要实现一个新版本的 adder,但是如果我不想这样做怎么办?如果我想明确使用 trait OneTwo 中显式包含的 adder 实现呢?


如果您在特质中的adder方法上添加override关键字,则将选择最后一个实现(从左到右)。在这种情况下,是Two。但是依赖于声明顺序并不是一个好的设计。 - jpmelanson
2个回答

9

您可以将其作为修饰符指定给 superoverride def adder() = super [One] .adder()。还要注意,这是编译时错误,而不是运行时错误!


嗯,根据我的IntelliJ版本不是这样的。至少在我调用脚本解释器之前它并没有将其标记为错误。谢谢。 - Jason
IntelliJ有时会忽略这些更复杂的继承和类型系统错误。如果你从(比如说)SBT运行它,你就能看到编译问题。 - marios
1
在IntelliJ中构建项目(Ctrl + F9)将显示实际的编译错误和警告(在某些更改中需要“重新构建项目”)。不要相信输入时显示的错误:它既可能错过实际的错误,也可能显示虚假的错误。 - Alexey Romanov

1
一种方法是重写 adder 方法,只调用其父类的 adder 方法。在这种情况下,它将是实现 adder 方法的最右边的 trait/class(在下面的示例中,它将是 One trait 的 adder 方法)。
class WhichOne(var x:Int = 10) extends Base with Two with One {
   override def adder() = super.adder()
}

海报提到他无法添加覆盖选项。 - jpmelanson
对他来说,添加一个要求重新实现该方法的覆盖是不可行的选择。这个只是使用super(所以这里并没有重新实现任何逻辑)。 - marios
一般来说,super 引用的是最右边混入的 trait,如果有的话? - Jason
这涉及到Scala如何解决多重继承中的“钻石问题”。这个链接有更多细节。通常情况下,最右边的trait通常是您的第一个入口点(因此它们的方法将首先被执行)。 - marios

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接