gpt4 book ai didi

scala - 可堆叠特征模式: method's implementation “needs ` abstract override' modifiers”

转载 作者:行者123 更新时间:2023-12-04 13:18:57 25 4
gpt4 key购买 nike

最近,我发现了关于可堆叠特征模式的信息,并按照here描述的示例进行了学习。一切正常,但有一种情况我无法理解:

trait A { 
def test : String
}
trait B extends A {
// 'abstract override' modifier required as
// the test() method is not yet implemented
abstract override def test = {
s"B${super.test}"
}
}
class C extends A with B {
// test method concrete implementation
override def test = { "C" }
}

<console>:10: error: overriding method test in trait B of type => String;
method test needs `abstract override' modifiers
class C extends A with B { override def test = { "C" } }

我不明白为什么它不能编译,以及为什么C::test方法需要提到的修饰符。

我注意到为了进行此编译,我可以做两个修改,可以通过在运行时编写C类来完成:
class C extends A { override def test = { "C" } }
new C with B // works as expected

或通过添加一个额外的类(有点相同,但在编译时):
class C extends A { 
override def test = { "C" }
}
class D extends C with B

new D().test
res5: String = BC

为什么我需要一个额外的类(哪个BTW扮演 Basic class的角色)?

最佳答案

出现这种情况的原因是Scala的类线性化,用于解决歧义和abstract override的语义。但是首先是第一件事。

类线性化

每当您具有类型a的实例A并在其上调用a.foobar()的方法时,编译器都必须弄清楚在哪里可以找到foobar的定义。由于A可以扩展任何其他类和一组特征,因此foobar函数可能有多个定义。为了解决这些歧义,Scala将使用其所有父类(super class)和特征线性化您的类A。线性化将产生一个顺序,在该顺序中检查不同类型的foobar的定义。第一个匹配项将是执行的功能。

Scala规范定义了线性化,如下所示

Definition 5.1.2 Let C be a class with template C1 with ... with Cn { stats }. The linearization of C, L(C) is defined as follows: L(C) = C , L(Cn)+: ... +: L(C1)

Here +: denotes concatenation where elements of the right operand replace identical elements of the left operand.



由于所有理论都是灰色的,因此让我们看一个例子:
trait T1 {
def foobar() = 1
}

trait T2 {
def foobar() = 2
}

class B extends T2 {
override def foobar() = 42
}

class A extends B with T1 with T2 {
override def foobar() = super.foobar()
}

首先,我们必须在类 foobar中重写 A方法,因为我们对此有多个竞争定义。但是,现在的问题是, super.foobar调用哪种方法定义。为了找到答案,我们必须计算 A的线性化。
L(A) = A, L(T2) +: L(T1) +: L(B)
L(B) = B, L(T2)
L(T2) = T2
L(T1) = T1
L(A) = A, T2 +: (T1, B, T2)
L(A) = A, T1, B, T2

因此, super.foobar将调用 T1中的定义,该定义返回 1

抽象覆盖

方法的 abstract override修饰符基本上说必须有一个实现此方法的类/特征 I,它在实例化的类的线性化中以 abstract override修饰符出现在特征之后。这是执行 super.foobar()所必需的,因为 super.foobar()要求进一步搜索线性化以获取 foobar的定义。

现在,当您查看类 C的定义时,您将看到它具有以下线性化
 C, B, A

因此,它无法编译,因为从 B开始,您找不到 test的实现。

现在,当我们查看有效的示例时,我们将说明它们为何真正起作用。对于 C extends Anew C with B的情况,基本上是创建一个匿名类 Z extends C with BZ的线性化为
Z, B, C, A

在这里,您可以看到 B可以在 C中找到 test的实现。因此,代码可以编译。类 D的示例也是如此。

关于scala - 可堆叠特征模式: method's implementation “needs ` abstract override' modifiers”,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32511722/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com