实现具有特征、不一致的编译器行为的抽象方法?
我有一个来自 Java 库的基类,我无法修改其代码。这个类 (A) 有一个空方法 (b),它应该被声明为抽象:
class A {
def b { }
}
我在 Scala 中扩展这个类并重写该方法以使其抽象:
abstract class AA extends A {
override def b
}
现在我在一个特征中实现这个方法:
trait B {
def b { println("B") }
}
如果我用以下方法扩展 AA特征 B,我收到错误:重写类型 => 的 A 类中的方法 b单元; 类型 => 的特质 B 中的方法 b单元需要“override”修饰符:
class C extends AA with B {}
相反,如果代码是这样的,则所有内容都会编译而不会出现错误,这对我来说似乎有点矛盾:
abstract class AA {
def b
}
trait B {
def b { println("B") }
}
class C extends AA with B {}
我正在运行 Scala 2.8.0RC3,并且对该语言完全陌生(3 天) 。另一个奇怪且相关的行为是,在使 b 抽象时不需要覆盖标签:
abstract class AA extends A {
def b
}
I have a base class that comes from a Java library, whose code I cannot modify. This class (A) has an empty method (b) which should have been declared as abstract instead:
class A {
def b { }
}
I extend this class in Scala and override the method to make it abstract:
abstract class AA extends A {
override def b
}
Now I implement this method in a trait:
trait B {
def b { println("B") }
}
If I extend AA with trait B, I get a error: overriding method b in class A of type => Unit;
method b in trait B of type => Unit needs `override' modifier:
class C extends AA with B {}
Instead, if the code had been like this, everything is compiled without errors, which seems a bit contradictory to me:
abstract class AA {
def b
}
trait B {
def b { println("B") }
}
class C extends AA with B {}
I'm running Scala 2.8.0RC3, and completely new to the language (3 days). Another weird and related behaviour is that the override label is not necessary when making b abstract:
abstract class AA extends A {
def b
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
为了尝试了解发生了什么,我尝试了以下操作:
显然,问题的根源在于抽象类无法“释放”其超类中的方法,使抽象类的子类不需要包含“覆盖”修饰符。
To try to see what's going on, I tried this:
Apparently, the source of the problem is that abstract classes can't "free up" methods in their superclass from the need for the abstract class's subclasses to include the 'override' modifier.
不确定这是否是正确的解决方案,但如果您的
trait B
扩展A
(并覆盖b
),那么一切都可以正常编译:首先让我们定义
A
和AA
就像你在问题中呈现它们一样:你做了什么:
我对特征 B 尝试了什么(为了能够添加 '
override
'):所以现在:
使用
Cb
调用正确的b
重写方法至于您明显的“不一致”,请参阅 Scala for Java 难民第 5 部分:特征和类型:
因此,在第二个示例中不需要
override
关键字。Not sure if this is the right solution, but if your
trait B
extendsA
(and overrideb
), then everything compile fine:First let's define
A
andAA
like you present them in your question:What you did:
What I tried with trait B (in order to be able to add the '
override
'):So now:
The right
b
overriden method is called withC.b
As for your apparent "inconsistency", see Scala for Java Refugees Part 5: Traits and Types:
So no need for
override
keyword in your second example.问题非常微妙。根据经验,您的类 AA 扩展了 A,应该与扩展 A 的特征混合在一起。
你做到了:
因此,当你混合 AA 和 B 方法时,b 被定义了两次。一次由A(未覆盖,因为B中的定义替换了AA中的覆盖),第二次由B ,编译器无法选择其中之一,因为这两个(名称相同但不相关)方法之间没有层次结构。如果你愿意的话,可以这样想:编译器“混合”了AA和B的主体;如果他选择 AA 中的方法,那么它将是抽象的,如果他选择 B 中的方法(应该发生什么),因为它不是覆盖,你只能使用两种方法b。
为了解决这个问题,您需要确保两个方法
覆盖
相同的方法,在这种情况下,编译器会理解您正在谈论相同的方法,并优先考虑最后一个混合的特征。现在,要重写 B 中的方法 b,该类还必须从 A 继承。因此,执行此操作的规范方法是:
编译得很好。
现在,当您这样做时:
很明显,这两种方法是相同的,因此编译器知道他必须使用特征中的方法。
其他解决方案包括:
同样,这个问题非常微妙,但我希望我能说得更清楚一些。要更好地理解,请阅读 Scala 的 Stackable Trait Pattern。
The problem is very subtle. As a rule of thumb, your class AA, which extends A, should be mixed with traits that also extend A.
You did:
Hence when you mix AA and B method b is DEFINED twice. Once by A (Not overrided because the definition in B replaced the override in AA) and the second by B, the compiler can't chose one over the other because there is no hierarchy between the two (equaly named but unrelated) methods. If you want, think about it like this: The compiler "mixes" the bodies of AA and B; if he choses the method from AA it will be abstract, if he choses the method from B (What should happend), since it's not an override, your stuck with two methods b.
To solve this, you want to make sure that both methods
override
the same method, in which case the the compiler will understand you are talking about the SAME method and will give priority to the last trait mixed.Now, to override the method b in B, that class has also to inherit from A. So the canonical way to do this would be:
Which compiles just fine.
Now, when you do:
it's clear that both methods are the same so the compiler knows he has to use the method from the trait.
Other solutions include:
Again, the problem is very subtle but I hope I made it a little clearer. To get a better understandig read Scala's Stackable Trait Pattern.