Scala之旅——抽象类型

特质和抽象类可以拥有抽象类型的成员。这意味着具体的实现可以定义实际的类型,下面是示例:

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

这里我们定义了一个抽象的type T,用来描述element的类型。我们可以在抽象类中继承该特质,并为T增加了一个类型上界使之更为具体。

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

注意我们将如何使用作为类型上界的另一个抽象的type Uclass SeqBuffer通过声明一个Seq[U](这里U是一个新的抽象类型)的子类型T,使得我们在一个Buffer中只能存储序列。

拥有抽象成员的特质和经常与匿名类的实例化结合使用。为了说明这点,我们来看一段程序,其中涉及到一个指向整数列表的序列缓冲:

1
2
3
4
5
6
7
8
9
10
11
12
13
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]

也可以将抽象类型成员转换为类的类型参数,反之亦然。下面是上述代码的另外一个版本,但仅仅使用了类型参数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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])。此外,有些场景下是不能用类型参数来替换抽象类型的。

小鹏 wechat
公众号:数据Man
0%