Вы параметризуете методы с другим параметром типа A
, который отличается от одного из определения вашего класса. Вот версия, которую вы написали с переименованными параметрами:
trait HasBuffer[+A] {
var items = Buffer[A]()
def add[B](item: B) = items += item
def remove[B](item: B) { items -= item }
def set(is: Buffer[A]) { items = is }
def clear { items clear }
}
Теперь должно быть понятно, почему компилятор это отвергает.
Вместо этого вы можете просто написать такие методы:
def add(item: A) = items += item
def remove(item: A) { items -= item }
Однако тогда вы все равно будете получать ошибки компилятора о том, что ковариантный тип A
встречается в противоположных и инвариантных позициях.
Смысл ковариантности заключается в том, что если вы ожидаете HasBuffer[AnyVal]
, то вы можете перейти в HasBuffer[Int]
. Однако, если вы ожидаете AnyVal
и будете использовать этот тип также для метода add
, вы сможете добавить совершенно другой тип к вашему HasBuffer[Int]
. Следовательно, компилятор отклоняет это.
Вместо этого вам нужно будет указать нижнюю границу параметра типа, например:
trait HasBuffer[+A, V <: A] {
var items = Buffer[V]()
def add(item: V) = items += item
def remove(item: V) { items -= item }
def set(is: Buffer[V]) { items = is }
def clear { items clear }
}
Теперь у вас могут быть такие методы:
def doSomething[X <: AnyVal](b : HasBuffer[AnyVal, X], e : X) = b.add(e)
Этот метод будет работать со всеми видами комбинаций параметров типа HasBuffer
, которые удовлетворяют требуемой нижней границе.
Мысленно сравните это с идеей отсутствия нижней границы. Тогда метод стал бы примерно таким:
// doesn't make much sense!
def doSomething(b : HasBuffer[AnyVal], e : AnyVal) = b.add(e)
Если вы вызовете это с объектом типа HasBuffer[Int]
и Double
, все будет в порядке. Вы, вероятно, не будете счастливы позже, когда вы обнаружите, что ваш буфер, который должен содержать только Int
s, теперь содержит Double
.