使用特征,不一致的编译器行为实现抽象方法?

A.R*_*A.R 6 scala traits

我有一个来自Java库的基类,其代码我无法修改.这个类(A)有一个空方法(b),它应该被声明为abstract:

class A {
  def b { }
}
Run Code Online (Sandbox Code Playgroud)

我在Scala中扩展此类并重写该方法以使其成为抽象:

abstract class AA extends A {
  override def b
}
Run Code Online (Sandbox Code Playgroud)

现在我在一个特征中实现这个方法:

trait B {
  def b { println("B") }
}
Run Code Online (Sandbox Code Playgroud)

如果我用特征B扩展AA,我会得到一个错误:在类A中覆盖方法b => Unit; 特征B中的方法b类型=>单位需要`覆盖'修饰符:

class C extends AA with B {}
Run Code Online (Sandbox Code Playgroud)

相反,如果代码是这样的,那么编译所有内容都没有错误,这对我来说似乎有些矛盾:

abstract class AA {
  def b
}

trait B {
  def b { println("B") }
}

class C extends AA with B {}
Run Code Online (Sandbox Code Playgroud)

我正在运行Scala 2.8.0RC3,并且对语言完全陌生(3天).另一个奇怪的和相关的行为是在制作b abstract时不需要覆盖标签:

abstract class AA extends A {
  def b
}
Run Code Online (Sandbox Code Playgroud)

小智 5

为了试着看看发生了什么,我尝试了这个:

scala> class A{
     |   def b{ }
     | }
defined class A

scala> abstract class AA extends A{
     |   override def b
     | }
defined class AA

scala> class AAA extends AA{
     |   def b = println("AAA")
     | }
<console>:8: error: overriding method b in class A of type => Unit;
 method b needs `override' modifier
         def b = println("AAA")
             ^
Run Code Online (Sandbox Code Playgroud)

显然,问题的根源是抽象类不能"释放"从他们需要超方法抽象类的子类包括"覆盖"修饰.


Von*_*onC 2

不确定这是否是正确的解决方案,但如果您的trait Bextends A(和 override b),那么一切都可以正常编译:

\n

首先让我们定义AAA像您在问题中呈现它们一样:

\n
C:\\Users\\VonC>scala\nWelcome to Scala version 2.8.0.RC5 (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_18).\nType in expressions to have them evaluated.\nType :help for more information.\n\nscala> class A {\n     | def b { println("A b") }\n     | }\ndefined class A\n\nscala> new A\nres5: A = A@153bedc4\n\nscala> res5.b\nA b\n\nscala> abstract class AA extends A {\n     | override def b\n     | }\ndefined class AA\n
Run Code Online (Sandbox Code Playgroud)\n

你做了什么:

\n
scala> trait B {\n     | override def b { println("B b") }\n     | }\n<console>:6: error: method b overrides nothing\n       override def b { println("B b") }\n                    ^\n
Run Code Online (Sandbox Code Playgroud)\n

我对特征 B 的尝试(为了能够添加 \' override\'):

\n
scala> trait B extends A {\n     | override def b { println("B b") }\n     | }\ndefined trait B\n
Run Code Online (Sandbox Code Playgroud)\n

所以现在:

\n
scala> class C extends AA with B {}\ndefined class C\n\nscala> new C\nres7: C = C@1497b7b1\n\nscala> res7.b\nB b\n
Run Code Online (Sandbox Code Playgroud)\n

b调用正确的重写方法C.b

\n
\n

至于您明显的“不一致”,请参阅Scala for Java Refugees Part 5: Traits and Types

\n
\n

首先,有\xe2\x80\x99s那个令人讨厌的override关键字。我在有关基本 OOP 的文章中提到过,任何重写超类中方法的方法都必须使用 override 修饰符进行声明。当时,我将其比作强制使用注释的语言@Override,其主要目的是强制执行良好实践。

\n

特性的威力的真正关键在于编译器在继承类中处理它们的方式。
\n Traits 实际上是 mixin,而不是真正的父类
\n任何非抽象特征成员实际上都包含在继承类中,就像类的物理部分一样。好吧,虽然不是物理上的,但你明白了。
\n\n\n\xe2\x80\x99s 就好像编译器对非抽象成员执行剪切和粘贴并将它们插入到继承类中。这意味着继承路径中\xe2\x80\x99s没有歧义,意味着不存在菱形问题。

\n
\n

override因此,在第二个示例中不需要关键字。

\n