是否可以覆盖类型字段?

时间:2012-06-30 14:10:58

标签: scala types

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}
                                           ^

在上面的示例中,我收到一条错误消息,我无法覆盖类A中的类型字段(即使所选类型subC扩展了类C)。

是否可以覆盖类型字段?如果是的话,上面的例子有什么问题?

1 个答案:

答案 0 :(得分:25)

你不会谈论关于类型的'覆盖',而是缩小它们的界限。

  1. type T ...无界限
  2. type T <: C ... TCC的子类型(称为上限
  3. type T >: C ... TC或超级C(称为下限
  4. type T = C ... T正好是C(类型别名)
  5. 因此,如果T是特质A的类型成员,而SubAA的子类型,则情况(2)SubA可能将T缩小到更具体的子类型C,而在情况(3)中,它可以将其缩小到更高的C超类型。案例(1)不对SubA施加任何限制,而案例(4)意味着T可以说是'最终'。


    这会对TA的可用性产生影响 - 它是否可能显示为方法参数的类型或方法的返回类型。

    示例:

    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
    }
    

    可以在m中定义方法MayNarrow1,因为类型T出现在逆变位置(作为方法参数的类型),因此它仍然是即使在T的子类型中缩小MayNarrow1也是有效的(方法正文可以将t视为类型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 {}
    }