Это фундаментальная особенность объектно-ориентированного программирования, которая не получает столько внимания, сколько заслуживает.
Предположим, у вас есть коллекция 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 сделать его еще сложнее, если вы не сделаете его инвариантным.Я рекомендую делать это и распространять дженерики и дисперсию в другом месте.Но мне нужно увидеть больше деталей, чтобы убедиться, что это подойдет для вашего варианта использования.