Scala特征及其方法的参数化

non*_*com 3 methods scala traits type-parameter

在我的应用程序中,我想使用这样的特性:

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 }
}
Run Code Online (Sandbox Code Playgroud)

继承此特征的类应该能够缓冲作为类A的子类的任何类的实例.但是,在添加和删除方法上,编译器都抱怨正在添加或删除项目"类型不匹配;找到:需要item.type(带底层类型A):".我该怎么理解这个?这里我的错误是什么,该怎么办?

Fra*_*ank 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 }
}
Run Code Online (Sandbox Code Playgroud)

现在应该清楚,为什么编译器会拒绝这一点.

相反,您可以简单地编写如下方法:

def add(item: A) = items += item
def remove(item: A) { items -= item }
Run Code Online (Sandbox Code Playgroud)

但是,您仍然会收到编译器错误,指出协变类型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 }
}
Run Code Online (Sandbox Code Playgroud)

有了这个,您现在可以使用以下方法:

def doSomething[X <: AnyVal](b : HasBuffer[AnyVal, X], e : X) = b.add(e)
Run Code Online (Sandbox Code Playgroud)

此方法适用于HasBuffer满足所需下限的各种类型参数组合.

在心理上将其与不提供下限的想法进行比较.然后该方法将成为这样的事情:

// doesn't make much sense!
def doSomething(b : HasBuffer[AnyVal], e : AnyVal) = b.add(e)
Run Code Online (Sandbox Code Playgroud)

如果调用此方法,类型的对象HasBuffer[Int]Double它会高兴.你可能不会后来开心,当你发现你的缓冲区应该只包含Ints时现在包含一个Double.