泛型類別是將型別視為參數的類別。它們對於集合類別特別有用。
定義泛型類別
泛型類別會在方括號 []
中將型別視為參數。一個慣例是使用字母 A
作為型別參數識別碼,不過可以使用任何參數名稱。
class Stack[A] {
private var elements: List[A] = Nil
def push(x: A): Unit =
elements = x :: elements
def peek: A = elements.head
def pop(): A = {
val currentTop = peek
elements = elements.tail
currentTop
}
}
class Stack[A]:
private var elements: List[A] = Nil
def push(x: A): Unit =
elements = x :: elements
def peek: A = elements.head
def pop(): A =
val currentTop = peek
elements = elements.tail
currentTop
這個 Stack
類別的實作將任何型別 A
視為參數。這表示底層清單 var elements: List[A] = Nil
只能儲存型別 A
的元素。程序 def push
只接受型別 A
的物件(注意:elements = x :: elements
將 elements
重新指定為一個新的清單,方法是將 x
加到目前的 elements
之前)。
此處的 Nil
是空的 List
,不要與 null
混淆。
用法
若要使用泛型類別,請將型別放入方括號中,取代 A
。
val stack = new Stack[Int]
stack.push(1)
stack.push(2)
println(stack.pop()) // prints 2
println(stack.pop()) // prints 1
val stack = Stack[Int]
stack.push(1)
stack.push(2)
println(stack.pop()) // prints 2
println(stack.pop()) // prints 1
實例 stack
只能接受 Int。但是,如果類型參數有子類型,則可以傳遞
class Fruit
class Apple extends Fruit
class Banana extends Fruit
val stack = new Stack[Fruit]
val apple = new Apple
val banana = new Banana
stack.push(apple)
stack.push(banana)
class Fruit
class Apple extends Fruit
class Banana extends Fruit
val stack = Stack[Fruit]
val apple = Apple()
val banana = Banana()
stack.push(apple)
stack.push(banana)
類別 Apple
和 Banana
都擴充 Fruit
,因此我們可以將實例 apple
和 banana
推送到 Fruit
的堆疊中。
注意:泛型類型的子類型是 *不變* 的。這表示如果我們有一個類型為 Stack[Char]
的字元堆疊,則無法將它用作類型為 Stack[Int]
的整數堆疊。這是不健全的,因為它會讓我們能夠在字元堆疊中輸入真正的整數。結論是,Stack[A]
僅當且僅當 B = A
時才是 Stack[B]
的子類型。由於這可能會相當具有限制性,因此 Scala 提供了一個 類型參數註解機制 來控制泛型類型的子類型行為。