19
scala> class C
defined class C

scala> class subC extends C
defined class subC

scala> class A { type T = C}
defined class A

scala> class subA extends A { override type T = subC}
<console>:10: error: overriding type T in class A, which equals C;
 type T has incompatible type
      class subA extends A { override type T = subC}
                                           ^

In the example above, I get an error message, that I can not override the type field in class A ( even if the chosen type subC extends the class C).

Is overriding a type field possible at all ? And if yes, what is wrong with the example above ?

4

1 回答 1

27

你不会说关于类型的“覆盖”,而是缩小它们的界限。

  1. type T...没有界限
  2. type T <: C...TC或子类型C(称为上限
  3. type T >: C...TC或超类型C(称为下界
  4. 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 {}
}
于 2012-06-30T14:33:00.650 回答