Scala 为什么可以';一个类不能用相同签名的方法扩展traits吗?

Scala 为什么可以';一个类不能用相同签名的方法扩展traits吗?,scala,overriding,traits,Scala,Overriding,Traits,为什么我会得到下面的错误?如何解决这个问题 我假设,由于A和B编译为(接口、类)对,所以在编译C时选择正确的静态方法调用是一个问题。我希望优先级是根据顺序来确定的 scala> trait A { def hi = println("A") } defined trait A scala> trait B { def hi = println("B") } defined trait B scala> class C extends B with A <console

为什么我会得到下面的错误?如何解决这个问题

我假设,由于A和B编译为(接口、类)对,所以在编译C时选择正确的静态方法调用是一个问题。我希望优先级是根据顺序来确定的

scala> trait A { def hi = println("A") }
defined trait A

scala> trait B { def hi = println("B") }
defined trait B

scala> class C extends B with A
<console>:6: error: error overriding method hi in trait B of type => Unit;
 method hi in trait A of type => Unit needs `override' modifier
       class C extends B with A

scala> trait A { override def hi = println("A") }
<console>:4: error: method hi overrides nothing
       trait A {override def hi = println("A")}
scala>trait A{def hi=println(“A”)}
定义特征A
scala>trait B{def hi=println(“B”)}
定义性状B
scala>C类用A扩展了B
:6:错误:错误覆盖类型=>Unit的特性B中的方法hi;
类型=>Unit的特性A中的方法hi需要“override”修饰符
C类用A扩展B
scala>trait A{override def hi=println(“A”)}
:4:错误:方法hi不覆盖任何内容
特征A{override def hi=println(“A”)}
请注意,在Ruby中,这很好地工作:

>模块B;def hi;把‘B’放进去;终止终止
=>零
>>模块A;def hi;放‘A’;终止终止
=>零
>>丙级;;包括:;包括B;终止
=>C
>>c=c新
=> #
>>你好
B
=>零

您可以使用一个共同的基本特征,例如
base
,如下所示:

trait Base {def hi: Unit}
trait A extends Base {override def hi = println("A")}
trait B extends Base {override def hi = println("B")}
class C extends A with B
对于类型层次结构,调用
hi
的结果如下(注意使用
{}
实例化特征):


这是最新的。应该继承哪个方法,是A方法还是B方法?你可以按照Don的建议,通过使用一个公共的基本特征来解决这个问题。

一个特征将方法添加到将其混合在一起的类中。如果两个traits添加了相同的方法,那么这个类将得到两个相同的方法,当然,这是不可能的

但是,如果该方法在trait中是私有的,则不会引起问题。如果你想让这些方法相互叠加,你可以定义一个基本特征,然后对继承的特征进行
abstract override
。但是,它需要一个类来定义方法。以下是一个例子:

scala> trait Hi { def hi: Unit }
defined trait Hi

scala> trait A extends Hi { abstract override def hi = { println("A"); super.hi } }
defined trait A

scala> trait B extends Hi { abstract override def hi = { println("B"); super.hi } }
defined trait B

scala> class NoHi extends Hi { def hi = () }
defined class NoHi

scala> class C extends NoHi with B with A
defined class C

scala> new C().hi
A
B

但是,如果您真的希望每个trait有两个独立的方法,那么您需要编写而不是继承。

这在2.8和2.11中对我有效,并允许您在traits
A
B
中不介入:

trait A { def hi = println("A") }
trait B { def hi = println("B") }

class C extends A with B {
  override def hi = super[B].hi
  def howdy = super[A].hi // if you still want A#hi available
}

object App extends Application {
  (new C).hi // prints "B"
}

我也有同样的问题,我不喜欢创建一个中间特征,因为我可以使用相同的方法创建4、5甚至6个特征,因为它包含CRUD操作(查找、创建…)。此外,我只需要将这些特性结合起来用于测试目的,我总是尽量避免修改项目的结构,只是为了让测试更容易。 所以我只是在不同的对象中实现了这些特性:

class somethingToTest {
  object AImpl extends ATrait 
  object BImpl extends BTrait

  val a = AImpl.methodDuplicated()
  val b = BImpl.methodDuplicated()
}

这可能不是使用traits的最聪明的方法,但它不需要对项目的代码进行任何更改,它只意味着在测试中有更多的代码。

谢谢。我有点希望找到一个非侵入性的解决方案。一些可以用C单独完成的事情(好像A和B来自不同的第三方库),为什么不让编译器选择一个方法作为实现方法呢?由于A和B被编译为使用静态方法连接A和类A$class,那么在JVM中,C完全可以同时实现A和B,方法hi在C中的实现可以调用$class。请注意,在您的回答中,C最终会得到两个(甚至三个)相同的方法,所以这件事是可以做到的。如果一个人愿意抛弃继承的概念基础,是的,这是可以做到的——以后可能会后悔。如果你想要合成,就要合成,不要继承。我说过编译器可以任意选择要使用的方法,并指出这在底层实现中是可能的。在Mitch的解决方案中,您需要显式地编写“override def hi=super[B].hi”。编译器将其作为默认实现(也就是说,您仍然可以使用任何您想要的重写)来为您执行,这有什么错呢?请参阅我的Ruby示例,其中一切都正常。这是决定“super”的语义的问题。我可以建议,在扩展特征树中,选择第一个DFS。注意这里也没有钻石。恰恰相反,解决方案是创造一个基本特征,从而创造一个钻石。所以钻石是一个解决方案,而不是一个问题在Scala中没有钻石问题,因为…太棒了!太糟糕了,如果我尝试“C类用B扩展A”,错误没有提到这种解决冲突的方法。@IttayD with Scala 2.10.4:错误消息说明了如何解决这个问题:(注意:这可以通过在C类中声明重写来解决。)C类用B扩展A{
class somethingToTest {
  object AImpl extends ATrait 
  object BImpl extends BTrait

  val a = AImpl.methodDuplicated()
  val b = BImpl.methodDuplicated()
}