特质和抽象类可以包含一个抽象类型成员,意味着实际类型可由具体实现来确定。例如:

    1. trait Buffer {
    2. type T
    3. val element: T
    4. }

    这里定义的抽象类型T是用来描述成员element的类型的。通过抽象类来扩展这个特质后,就可以添加一个类型上边界来让抽象类型T变得更加具体。

    1. abstract class SeqBuffer extends Buffer {
    2. type U
    3. type T <: Seq[U]
    4. def length = element.length
    5. }

    注意这里是如何借助另外一个抽象类型U来限定类型上边界的。通过声明类型T只可以是Seq[U]的子类(其中U是一个新的抽象类型),这个SeqBuffer类就限定了缓冲区中存储的元素类型只能是序列。

    含有抽象类型成员的特质或类(classes)经常和匿名类的初始化一起使用。为了能够阐明问题,下面看一段程序,它处理一个涉及整型列表的序列缓冲区。

    1. abstract class IntSeqBuffer extends SeqBuffer {
    2. type U = Int
    3. }
    4. def newIntSeqBuf(elem1: Int, elem2: Int): IntSeqBuffer =
    5. new IntSeqBuffer {
    6. type T = List[U]
    7. val element = List(elem1, elem2)
    8. }
    9. val buf = newIntSeqBuf(7, 8)
    10. println("length = " + buf.length)
    11. println("content = " + buf.element)

    这里的工厂方法newIntSeqBuf使用了IntSeqBuf的匿名类实现方式,其类型T被设置成了List[Int]

    把抽象类型成员转成类的类型参数或者反过来,也是可行的。如下面这个版本只用了类的类型参数来转换上面的代码:

    1. abstract class Buffer[+T] {
    2. val element: T
    3. }
    4. abstract class SeqBuffer[U, +T <: Seq[U]] extends Buffer[T] {
    5. def length = element.length
    6. }
    7. def newIntSeqBuf(e1: Int, e2: Int): SeqBuffer[Int, Seq[Int]] =
    8. new SeqBuffer[Int, List[Int]] {
    9. val element = List(e1, e2)
    10. }
    11. val buf = newIntSeqBuf(7, 8)
    12. println("length = " + buf.length)
    13. println("content = " + buf.element)

    需要注意的是为了隐藏从方法newIntSeqBuf返回的对象的具体序列实现的类型,这里的型变标号+T <: Seq[U])是必不可少的。此外要说明的是,有些情况下用类型参数替换抽象类型是行不通的。