在组件系统中,一个重要的议题就是如何抽象所需的组件。编程语言当中有两种最主要的抽象方式:参数化和抽象成员。前一种主要是函数式抽象方式,而后一种主要是面向对象的方式。传统意义上,Java对值提供函数式抽象,而对操作提供面向对象的抽象。Java 5.0所支持的泛型,对类型也提供了一定的函数式抽象。
Scala对于值和类型提供上述两者抽象模式的统一支持,值和类型都可以作为参数,也可以作为抽象成员。本节对这两种模式进行讨论,并且对Scala类型系统的很大一部分进行回顾。
下面这个类定义了一个可以读取和写入数值的单元(cell):
class GenCell[T](init: T) {
private var value: T = init
def get: T = value
def set(x: T): unit = { value = x }
}
这个类用一个类型参数T抽象了cell的值的类型,因此我们称GenCell为泛型(generic)。
与类相近,方法也可以有类型参数,下面这个swap方法交换两个cell的内容,只要它们包含的值类型相同:
def swap[T](x: GenCell[T], y: GenCell[T]): unit = {
val t = x.get; x.set(y.get); y.set(t)
}
下面这段程序创建两个整数单元,并且交换它们的值:
val x: GenCell[int] = new GenCell[int](1)
val y: GenCell[int] = new GenCell[int](2)
swap[int](x, y)
参数的实际类型用方括号括起来,用于替代类和方法定义中的形式参数。Scala定义了一套复杂的类型推理(type inference)系统,使得这两种情况下参数的实际类型都可以省略。类的方法和构造函数的类型参数对应的实际类型,可以通过局部类型推理(local type inference[41, 39])根据预期的返回值以及参数类型推理出来。因此,上面的程序可以写成这种省略参数类型的方式:
val x = new GenCell(1)
val y = new GenCell(2)
swap(x, y)