5. 抽象(Abstraction)
在組件系統中,一個重要的議題就是如何抽象所需的組件。編程語言當中有兩種最主要的抽象方式:參數化和抽象成員。前一種主要是函數式抽象方式,而後一種主要是面向對象的方式。傳統意義上,Java對值提供函數式抽象,而對操作提供面向對象的抽象。Java 5.0所支持的泛型,對類型也提供了一定的函數式抽象。
Scala對於值和類型提供上述兩者抽象模式的統一支持,值和類型都可以作爲參數,也可以作爲抽象成員。本節對這兩種模式進行討論,並且對Scala類型系統的很大一部分進行回顧。
5.1. 函數式抽象(Functional Abstraction)
下面這個類定義了一個可以讀取和寫入數值的單元(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)