Вы параметризуете методы другим параметром типа 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
, теперь он содержит Double
.
Да, я должен признать, что это объяснение очень детализировано и, таким образом, будет направлением для тех, кто может столкнуться с подобной проблемой. Что касается Scala-компилятора - слишком плохо, что он допускает такие эквивалентные именованные типы аппараметров. Было бы логично запретить их полностью. Поскольку никто не хотел бы называть его параметры типа подобными, и те, кто хотел бы это сделать, просто объявили бы плохой стиль кодирования. Обфускация кода - это боковая область, она не должна отображаться в обычном программировании. – noncom