Swift 泛型 (Generics)
泛型 (Generics) 讓你能寫出靈活、可重用的函式和型別,它們可以與任何型別一起工作,只要該型別滿足你定義的約束。
這是 Swift 最強大的特性之一。事實上,Swift 標準庫的大部分內容都是用泛型寫的。例如,Array<Element> 和 Dictionary<Key, Value> 都是泛型集合。
泛型函式
假設你要寫一個交換兩個變數值的函式。如果不用泛型,你可能要為 Int 寫一個,為 String 寫一個...這太麻煩了。
使用泛型,只需寫一次:
func swapTwoValues<T>(_ a: inout T, _ b: inout T) {
let temporaryA = a
a = b
b = temporaryA
}
<T>:這是一個佔位符型別名稱 (通常用 T, U, V 等單個大寫字母表示)。它告訴 Swift 「T 是一個型別」,但具體是什麼型別現在不用管,只要a和b是同一個型別T就好。
var someInt = 3
var anotherInt = 107
swapTwoValues(&someInt, &anotherInt)
// someInt 現在是 107
var someString = "hello"
var anotherString = "world"
swapTwoValues(&someString, &anotherString)
// someString 現在是 "world"
泛型型別
你也可以自定義泛型型別。例如實現一個泛型的 Stack (堆疊):
struct Stack<Element> {
var items = [Element]()
mutating func push(_ item: Element) {
items.append(item)
}
mutating func pop() -> Element {
return items.removeLast()
}
}
var stackOfStrings = Stack<String>()
stackOfStrings.push("uno")
stackOfStrings.push("dos")
型別約束 (Type Constraints)
有時候你不能接受「任何」型別,而是希望該型別必須遵循某個 Protocols 或繼承自某個 Class。
語法:func someFunction<T: SomeClass, U: SomeProtocol>(someT: T, someU: U)
例如,要寫一個函式能在陣列中找到某個值的索引,並不是所有型別都能用 == 比較。只有遵循 Equatable 協定的型別才能比較。
func findIndex<T: Equatable>(of valueToFind: T, in array:[T]) -> Int? {
for (index, value) in array.enumerated() {
if value == valueToFind {
return index
}
}
return nil
}