重写类型边界时出现不兼容的类型错误



无法弄清楚为什么scalac在这里不开心(2.12):

trait A {
type Self <: A
type X <: Self
}
trait B extends A {
override type Self <: B
override type X = C // error: overriding type X in trait A with bounds <: B.this.Self
}
trait C extends B {
override type Self = C
}

感觉是因为路径依赖类型,但我不明白到底出了什么问题,是否有解决它的好方法。

CB的一个子类型,BA的一个子类型,所以CA的子类型,但C不是ASelfBSelf的子类型。所以你不能覆盖(在B)AX具有上限Self(即ASelf),C不满足界限(即BSelf)。

trait A {
type Self <: A
type X <: Self
// implicitly[C <:< Self] // doesn't compile
}
trait B extends A {
override type Self <: B
// override type X = C 
// implicitly[C <:< Self] // doesn't compile
}
trait C extends B {
override type Self = C
}

CSelf等于C但这并不意味着ASelfBSelf

您可以使用下限修复编译

trait A {
type Self <: A
type X <: Self
}
trait B extends A {
override type Self >: C <: B // >: C is added
override type X = C 
}
trait C extends B {
override type Self = C
}

或者,如果您的意思是AX不是ASelf而是CSelf的子类型,则可以使用类型投影来指定它

trait A {
type Self <: A
type X <: C#Self // here
}
trait B extends A {
override type Self <: B
override type X = C
}
trait C extends B {
override type Self = C
}

我想误会是因为def

trait A {
def foo(): String = "A#foo()"
def bar(): String = s"bar=A#bar(), foo=${foo()}"
}
trait B extends A {
def foo(): String = "A#foo()"
}
trait C extends B {
override def foo(): String = "C#foo()"
}

当我们在Abar()中编写foo()时,我们实际上不是指Afoo(),而是实现的foo()。这是可能的,因为方法实现是在运行时延迟解析的。但是类型是在编译时尽早解决的。所以当你写的时候

trait A {
type Self <: A
type X <: Self
}

X的上界SelfASelf,而不是实现的Self

OOP原则说,在A内部你不能具体引用Cfoo()(除非你实例化C)。但是你可以在任何地方特指ASelfBSelfCSelf,类型投影A#SelfB#SelfC#Self

与Dmytro Mitin的回答略有不同的角度:如果你对B的定义是合法的,它可以进一步扩展

trait D extends B {
override type Self = D  // satisfies Self <: B
}

但是X <: Self不会成立(X仍然是C,继承自B)。

更一般地说,B中的约束应该意味着A中的约束,而它们不是;添加>: C下限可以解决这个问题。

最新更新