你不会说关于类型的“覆盖”,而是缩小它们的界限。
type T...没有界限
type T <: C...T是C或子类型C(称为上限)
type T >: C...T是C或超类型C(称为下界)
type T = C...T正是C(类型别名)
因此,如果T是 trait 的类型成员A,并且SubA是 的子类型A,在情况 (2)SubA中可能会缩小T到更特定的子类型C,而在情况 (3) 中可能会缩小到更高的超类型C。案例(1)没有对 施加任何限制SubA,而案例(4)可以说T是“最终的”。
这会对Tin的可用性产生影响——A无论它可能显示为方法参数的类型还是方法的返回类型。
例子:
trait C { def foo = () }
trait SubC extends C { def bar = () }
trait MayNarrow1 {
type T <: C // allows contravariant positions in MayNarrow1
def m(t: T): Unit = t.foo // ...like this
}
object Narrowed1 extends MayNarrow1 {
type T = SubC
}
object Narrowed2 extends MayNarrow1 {
type T = SubC
override def m(t: T): Unit = t.bar
}
可以定义方法minMayNarrow1因为 typeT出现在逆变位置(作为方法参数的类型),因此即使T在子类型中缩小它仍然有效MayNarrow1(方法体可以将t其视为 type C)。
相反,type T = C不可避免地修复T,这有点对应于制作方法final。通过修复T,它可以用于协变位置(作为方法的返回类型):
trait Fixed extends MayNarrow1 {
type T = C // make that T <: C to see that it won't compile
final def test: T = new C {}
}
您现在可以很容易地看到必须禁止进一步“覆盖” T:
trait Impossible extends Fixed {
override type T = SubC
test.bar // oops...
}
为了完整起见,下面是不太常见的下限情况:
trait MayNarrow2 {
type T >: SubC // allows covariant positions in MayNarrow2
def test: T = new SubC {}
}
object Narrowed3 extends MayNarrow2 {
type T = C
test.foo
}
object Narrowed4 extends MayNarrow2 {
type T = C
override def test: T = new C {}
}