在我的应用程序中,我想使用这样的特性:
trait HasBuffer[+A] {
var items = Buffer[A]()
def add[A](item: A) { items += item }
def remove[A](item: A) { items -= item }
def set(is: Buffer[A]) { items = is }
def clear { items clear }
}
继承此特征的类应该能够缓冲作为类A的子类的任何类的实例。但是,在添加和删除方法上,编译器都抱怨要在“类型不匹配”的项目中添加或删除项目;找到:item.type(带底层类型A)必需:A“。我该怎么理解这个?这里我的错误是什么?该怎么做?
答案 0 :(得分:5)
您正在使用与您的类定义不同的另一个类型参数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
时,您可能不会感到高兴。
答案 1 :(得分:4)
问题是你已经为另一个类型参数A
定义了添加和删除方法,虽然它具有相同的名称,但它实际上是一个新的类型参数。
这应该让你前进:
def add(item: A)
def remove(item: A)
编辑:弗兰克是对的,我忘了处理Buffer
在A
协变的事实,原始声明中A
明显处于逆变位置。因此,上述仅是OP问题的部分解决方案。