ковариантный тип T встречается в контравариантном положении

Я знаю, что этот вопрос уже задавали раньше, но либо ответы не относятся к этому случаю, либо я их не понимаю.

В принципе, почему не работает следующий (простой пример, который воссоздает мою проблему)?

class Test[+T] {
    var list: List[T] = _
}

У меня проблема в том, что у меня есть объект, которому я хочу передать экземпляр Test[Nothing] (пустой Test), и это не сработает, если я не сделаю Test ковариантным в T.


person sksamuel    schedule 29.01.2013    source источник


Ответы (1)


Создание ковариантного теста в T означает, что Test[A] является подтипом Test[Any] для любого A. Итак, давайте создадим Test:

val test_string = new Test[String]

Теперь у нас есть Test[String], а содержащийся list имеет тип List[String].

Поскольку Test[String] является подтипом Test[Any], должно быть разрешено следующее:

val test_any : Test[Any] = test_string

И теперь у нас есть Test[Any], и, следовательно, test_any.list имеет тип List[Any], что означает следующее:

test_any.list = List[Any]()

Это означает, что мы только что присвоили List[Any] члену списка test_strings, что не должно быть разрешено, поскольку предполагается, что это List[String], а не List[Any]. Это также означает, что вы можете добавить к списку что угодно, так как это тип List[Any].

person stew    schedule 29.01.2013
comment
Итак, как я могу изменить свой содержащий список в зависимости от параметра типа класса Test, или это невозможно? - person sksamuel; 29.01.2013
comment
@monkjack Вы можете сделать list a val: class Test[+T](val list: List[T]), но это не всегда может быть вариантом, в зависимости от того, когда вы инициализируете список. - person Malte Schwerhoff; 29.01.2013
comment
Да, я заметил, что это работает, к сожалению, я на самом деле делаю это json, и Джексон не будет разбирать конструктор класса AFAIK. Я мог бы посмотреть, смогу ли я обойтись без класса case в своих целях. - person sksamuel; 29.01.2013
comment
Конкретная проблема здесь заключается в том, что, определяя list как var, компилятор автоматически предоставляет метод мутатора def list_=(l: List[T]): Unit, и в этом методе параметр типа T не находится в ковариантной позиции. То же самое произойдет, если вы попытаетесь установить T как контравариантный из-за соответствующего метода доступа. Обходного пути нет, кроме установки T как невариантного или использования val для вашего списка. - person pagoda_5b; 29.01.2013