Как инициализировать ковариантную переменную? - PullRequest
9 голосов
/ 12 декабря 2011

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

ошибка компилятора: ковариантный тип T встречается в контравариантной позиции в типе T значения значения _ =

почему? как я могу это исправить?

Ответы [ 3 ]

17 голосов
/ 12 декабря 2011

Вы не можете иметь переменную ковариантного типа.Var означает наличие, среди прочего, публичного def v_=(newV: T), так что он заставляет T появляться в качестве обычного аргумента, который является противоположной позицией.Так что вы должны либо

  • отказаться от ковариации и объявить C [T], а не C [+ T]
  • make va val

Быть немногоБолее подробно о части «почему» в вашем вопросе. Делая T ковариантным параметром с + T, вы заявляете, что хотите, чтобы C [B] был подтипом C [A], если B является подтипом A. Это означает, что выwant to allow:

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

Чтобы это звучало, компилятор ограничивает место, где T может появиться в C. Для краткости и с небольшими упрощениями v не может появляться как параметр подпрограммы (или как типиз вар).В противном случае, после того, как вы инициализировали cb и ca, как описано выше, вы можете

ca.v = new A

Это будет разрешено, так как ca должен быть C[A], поэтому его переменная v имеет типA.Однако, поскольку C ковариантен в T, ca может (и имеет в этом примере) ссылаться на экземпляр C[B].Если бы это назначение было разрешено, тогда вы могли бы

val vInCb: B = cb.v

быть уверенным, что это даст вам B .Однако вы просто помещаете туда A через ссылку ca.Эта ситуация должна быть запрещена, и это, запрещая параметр ковариантного типа T как тип переменной.

10 голосов
/ 12 декабря 2011

Вы можете объявить его как private[this]:

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

Любое использование, которое вы пытаетесь не разрешить в этой области, будет небезопасным с ко-вариантом T.

2 голосов
/ 12 декабря 2011

Вы должны сделать это valvar всегда есть метод установки, где тип появляется в противоположной позиции.

...