class C [+T] {
var v : T = _
}
编译错误:协变类型T出现在值value_=
的T类型逆变位置为什么?我怎样才能修好它?
不能有协变类型的变量。一个变量相当于拥有一个公共的def v_=(newV: T)
,因此它使T作为一个常规参数出现,这是一个逆变位置。所以你必须要么
- 放弃协方差并声明C[T]而不是C[+T]
在你的问题的"为什么"部分更详细一点,通过使T是+T的协变参数,你声明如果B是a的子类型,你希望C[B]是C[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作为变量的类型,这种情况确实存在。
可以声明为private[this]
:
class C [+T] { private[this] var v : T = _ }
如果您尝试使用此作用域不允许的任何用法,对于协变T
来说都是不安全的。
你必须让它成为val
。var
总是有一个setter方法,当类型出现在逆变位置时