你可以重写trait B
(稍后更多关于你的目标,我认为这有点不同)
trait B extends A {
type MyType <: BInner with AInner
}
这是完全有道理的。type 的值B#MyType
可以被视为 aBInner
或 a AInner
。
您无需重复Abstract
,因为A
它已经是Abstract
. 您不必编写override
,因为这对于类型声明是隐含的。所以问题是为什么A#MyType
不作为AInner
?
这是 scala 语言规范对 volatile 类型的说明。
3.6 挥发性类型
类型易变性近似于类型参数或类型的抽象类型实例没有任何非空值的可能性。正如 (§3.1) 中所解释的, volatile 类型的值成员不能出现在路径中。如果一个类型属于以下四个类别之一,则该类型是易失性的: 如果满足以下两个条件之一,则具有 ... 和 Tn {R} 的复合类型 T1 是易失性的。1. T2, ..., Tn 之一是类型参数或抽象类型,或者 2. T1 是抽象类型,并且对于 j > 1 的细化 R 或类型 Tj 为复合类型贡献了一个抽象成员,或 3. T1, ..., Tn 之一是单例类型。这里,如果 S 包含一个也是 T 成员的抽象成员,则类型 S 将抽象成员贡献给类型 T 。如果 R 包含一个抽象声明,它也是 T 的成员,则细化 R 将抽象成员贡献给类型 T。如果类型指示符是 volatile 类型的别名,或者如果它指定具有 volatile 类型作为其上限的类型参数或抽象类型,则该类型指示符是 volatile。如果路径 p 的基础类型是易失的,则单例类型 p.type 是易失的。如果 T 是易失的,则存在类型 T forSome {Q } 是易失的。
规范中提到的其他重要项目是关于抽象类型覆盖:
另一个限制适用于抽象类型成员:具有 volatile 类型(第 3.6 节)作为其上限的抽象类型成员不能覆盖没有 volatile 上限的抽象类型成员。
编译器错误是:
error: overriding type MyType in trait A with bounds <: AInner;
type MyType is a volatile type; cannot override a type with non-volatile upper bound
这与规范一致。BInner with A#MyType
是易变的。在此之前MyType
有一个非易失性的 as Any
。
问题是 scala 类型系统中的类型必须具有唯一的含义。抽象类型可以被认为是声明被推迟到子类的类型。因此,在抽象类型仍然是抽象的时候声明它的值是没有问题的。另一方面,如果我们有一个类似的类型BInner with A#MyType
,这个类型可能有几个含义。它被称为 volatile 并且具有这种类型的非 null 值是没有意义的,因为它可以具有与实例化MyType
抽象类型的子类一样多的类型。为简化起见,我们可以将 volatile 类型视为不是子类型的类型Any
(而 volatile 视为子类型Any
)。因此,我们有一个编译器提到的矛盾。
回到你的目标,你说的
我在这里(在特征 B 中)试图实现的是进一步限制在 Abstract 中声明的 MyType 类型,因此 MyType 类型的任何值都必须扩展 mixin 树中的所有 MyType。
由于这样的内在特征,您可以实现这一目标。
trait Abstract {
type MyType
}
trait B extends Abstract {
trait MyType {
def bMethod : Int
}
}
trait A extends B {
trait MyType extends super.MyType {
}
}
嗯,我希望这有点你在找什么。