如何初始化协变变量?

时间:2011-12-12 11:11:44

标签: scala covariance

class C [+T] { var v : T = _ }

编译器错误:协变类型T出现在值值为_ =

的类型T的逆变位置

为什么呢?我该如何解决?

3 个答案:

答案 0 :(得分:17)

您不能拥有协变类型的var。 变量等于公共def v_=(newV: T),因此它使T看起来是一个常规参数,这是一个逆变位置。所以你必须

  • 放弃协方差并声明C [T]而不是C [+ T]
  • make v a val

要对你的问题的“为什么”部分稍微冗长一点,通过使T是带有+ T的协变参数,如果B是a,则表明你希望C [B]为C [A]的子类型A的子类型。这意味着你想允许:

val cb: C[B] = new C[B]
val ca : C[A] = cb    

为了发出这种声音,编译器会限制T在C中出现的位置。为了使其简短并且稍作简化,v不能作为例程的参数(或var的类型)出现。否则,在如上所述初始化cb和ca后,你可以

ca.v = new A

这是允许的,因为ca应该是C[A],因此其变量v的类型为A。但是,由于C在T中是协变的,ca可以(并且在示例中)引用C[B]实例。如果允许这个任务,你可以做

val vInCb: B = cb.v

相信这会给你一个 B 。但是,您只需通过ca引用添加 A 。必须禁止这种情况,并且禁止将协变类型参数T作为var的类型。

答案 1 :(得分:10)

您可以将其声明为private[this]

class C [+T] { private[this] var v : T = _ }

您尝试此范围不允许使用的任何用法都会因共变T而不安全。

答案 2 :(得分:2)

您必须将其设为valvar总是有一个setter方法,其中类型出现在逆变位置。