Ответ 1
Это фундаментальная особенность объектно-ориентированного программирования, которая не получает столько внимания, сколько она заслуживает.
Предположим, что у вас есть коллекция C[+T]
. Что означает +T
, так это если U <: T
, то C[U] <: C[T]
. Справедливо. Но что значит быть подклассом? Это означает, что каждый метод должен работать, работая над исходным классом. Итак, предположим, что у вас есть метод m(t: T)
. Это говорит, что вы можете взять любой t
и сделать с ним что-то. Но C[U]
может выполнять только действия с U
, которые могут быть не все t
! Таким образом, вы сразу же отклонили свое утверждение о том, что C[U]
является подклассом C[T]
. Не это. Есть вещи, которые вы можете сделать с помощью C[T]
, который вы не можете сделать с помощью C[U]
.
Теперь, как вы обходите это?
Один из вариантов - сделать инвариант класса (отбросить +
). Другой вариант заключается в том, что если вы примете параметр метода, чтобы разрешить любой суперкласс: m[S >: T](s: S)
. Теперь, если t
изменяется на U
, это не имеет большого значения: суперкласс из t
также является суперклассом U
, и этот метод будет работать. (Тем не менее, вы должны изменить свой метод, чтобы иметь возможность обрабатывать такие вещи.)
С классом case, еще труднее получить это право, если вы не сделаете его инвариантным. Я рекомендую это сделать и выталкивать дженерики и отклонения в другом месте. Но мне нужно будет увидеть более подробную информацию, чтобы быть уверенным, что это будет работать для вашего случая использования.