Scala:非法继承;自身类型Y不符合X的自身类型SELF。

17

我有一个带有类型参数的特质(trait),我想表达实现了这个特质的对象也会符合这个类型参数(使用泛型为了兼容Java)

以下是代码:

trait HandleOwner[SELF <: HandleOwner[SELF]] {
self : SELF =>
    // ...
    def handle: Handle[SELF]
}

trait Common[SELF <: Common[SELF]]  extends HandleOwner[SELF] {
    // ...
}

给我以下错误:

illegal inheritance;  self-type test.Common[SELF] does not conform to
test.HandleOwner[SELF]'s selftype SELF

如果我将 Common 改成:

trait Common[SELF <: Common[SELF]]  extends HandleOwner[SELF] {
self : SELF =>
    // ...
}

然后错误就消失了。

为什么我必须在每个非具体类型中重复相同的声明。如果我有一个基类,并说“extends Comparable”,只要具体类实现了compareTo方法,我不必在每个派生类型中重复“extends Comparable”。我认为这里应该是一样的。我只是说扩展HandleOwner也将是SELF,编译器应该接受它,并在考虑时考虑它,而不需要每个非具体子类型再次重复相同的事情。

我这样做是为了避免使用类转换,但我将从这个特性字面上扩展每个类,并且我不认为我应该重复这些声明数百甚至数千次!

1个回答

16

Self类型更类似于泛型约束而不是继承。对于class C[A <: B],约束必须在子类中一直重复出现:class D[A <: B] extends C[A]。约束必须重复出现,直到满足条件,也就是直到选择了实际参数类型,确实满足<: B。自身类型也是如此。编写self: A =>并不会使您的类型扩展A。它确保在实际实例化之前,它最终将与A混合在一起。

相反,当您扩展Comparable时,您已经使您的类成为一个Comparable,而不是为以后放置一个约束。但是,您需要实现compareTo的事实仍然必须随着abstract一直重复,直到您实际实现它。

当然,编译器可以避免重复<: Bself: A =>abstract,信息可用于它。这是语言设计者的选择。至少,必须重复self: A =>并不不同于其他任何地方的规则。


1
谢谢。这并不会让它变得不那么繁琐,但至少现在它有意义了。 - Sebastien Diot

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接