抽象类型
特质和抽象类可以拥有抽象类型的成员。这意味着具体的实现可以定义实际的类型,下面是示例:
trait Buffer {
type T
val element: T
}
这里我们定义了一个抽象的 type T ,用来描述 element 的类型。我们可以在抽象类中继承该特质,并为 T 增加了一个类型上界使之更为具体。
abstract class SeqBuffer extends Buffer {
type U
type T <: Seq[U]
def length = element.length
}
注意我们将如何使用作为类型上界的另一个抽象的 type U 。 class SeqBuffer 通过声明一个 Seq[U](这里 U 是一个新的抽象类型)的子类型 T ,使得我们在一个 Buffer 中只能存储序列。
拥有抽象成员的特质和类经常与匿名类的实例化结合使用。为了说明这点,我们来看一段程序,其中涉及到一个指向整数列表的序列缓冲:
abstract class IntSeqBuffer extends SeqBuffer {
type U = Int
}
def newIntSeqBuf(elem1: Int, elem2: Int): IntSeqBuffer =
new IntSeqBuffer {
type T = List[U]
val element = List(elem1, elem2)
}
val buf = newIntSeqBuf(7, 8)
println("length = " + buf.length)
println("content = " + buf.element)
这里的工厂方法 newIntSeqBuf 用到了 IntSeqBuf 的一个匿名实现类(即 new IntSeqBuffer ),并将 type T 设置为一个 List[Int] 。
也可以将抽象类型成员转换为类的类型参数,反之亦然。下面是上述代码的另外一个版本,但仅仅使用了类型参数:
abstract class Buffer[+T] {
val element: T
}
abstract class SeqBuffer[U, +T <: Seq[U]] extends Buffer[T] {
def length = element.length
}
def newIntSeqBuf(e1: Int, e2: Int): SeqBuffer[Int, Seq[Int]] =
new SeqBuffer[Int, List[Int]] {
val element = List(e1, e2)
}
val buf = newIntSeqBuf(7, 8)
println("length = " + buf.length)
println("content = " + buf.element)
为了隐藏方法 new IntSeqBuf 返回的对象的具体序列实现类型,我们需要用到型变注解(即 +T <: Seq[U] )。此外,有些场景下是不能用类型参数来替换抽象类型的。