泛型是 Swift 的強大特性之一,許多 Swift 標準庫是通過泛型代碼構建的。事實上,泛型的使用貫穿了整本語言手冊,只是你可能沒有發(fā)現(xiàn)而已。例如,Swift 的 Array 和 Dictionary 都是泛型集合。
泛型函數(shù)
func swapTwoValues<T>(inout a: T, inout _ b: T) {
let temporaryA = a
a = b
b = temporaryA
}
在大多數(shù)情況下,類型參數(shù)具有一個描述性名字,例如 Dictionary<Key, Value> 中的 Key 和 Value,以及 Array<Element> 中的 Element,這可以告訴閱讀代碼的人這些類型參數(shù)和泛型函數(shù)之間的關系。然而,當它們之間的關系沒有意義時,通常使用單一的字母來命名,例如 T、U、V,正如上面演示的 swapTwoValues(_:_:) 函數(shù)中的 T 一樣。
ps: 請始終使用大寫字母開頭的駝峰式命名法(例如
T和MyTypeParameter)來為類型參數(shù)命名,以表明它們是占位類型,而不是一個值。
--對于代碼命名規(guī)則來說,個人感覺此處很關鍵。所以下面把原版也搬過來
Always give type parameters upper camel case names(such as
TandMyTypeParameter) to indicate that they are a placeholder for a type,not a value.
泛型類型
除了泛型函數(shù),Swift 還允許你定義泛型類型。這些自定義類、結構體和枚舉可以適用于任何類型,如同 Array 和 Dictionary 的用法。
struct Stack<Element> {
var items = [Element]()
mutating func push(item: Element) {
items.append(item)
}
mutating func pop() -> Element {
return items.removeLast()
}
}
擴展一個泛型類型
當你擴展一個泛型類型的時候,你并不需要在擴展的定義中提供類型參數(shù)列表。更加方便的是,原始類型定義中聲明的類型參數(shù)列表在擴展中可以直接使用,并且這些來自原始類型中的參數(shù)名稱會被用作原始定義中類型參數(shù)的引用。
extension Stack {
var topItem: Element? {
return items.isEmpty ? nil : items[items.count - 1]
}
}
類型約束
swapTwoValues(::) 函數(shù)和 Stack 類型可以作用于任何類型。不過,有的時候如果能將使用在泛型函數(shù)和泛型類型中的類型,強制約束為某種特定類型,將會是非常有用的。類型約束可以指定一個類型參數(shù)必須繼承自指定類,或者符合一個特定的協(xié)議或協(xié)議組合。
func someFunction<T: SomeClass, U: SomeProtocol>(someT: T, someU: U) {
// 這里是泛型函數(shù)的函數(shù)體部分
}
關聯(lián)類型
定義一個協(xié)議時,有的時候聲明一個或多個關聯(lián)類型作為協(xié)議定義的一部分將會非常有用。關聯(lián)類型作為協(xié)議的一部分,為某個類型提供了一個占位名(或者說別名),其代表的實際類型在協(xié)議被采納時才會被指定。你可以通過 typealias 關鍵字來指定關聯(lián)類型。
protocol Container {
typealias ItemType
mutating func append(item: ItemType)
var count: Int { get }
subscript(i: Int) -> ItemType { get }
}
struct IntStack: Container {
// IntStack 的原始實現(xiàn)部分
var items = [Int]()
mutating func push(item: Int) {
items.append(item)
}
mutating func pop() -> Int {
return items.removeLast()
}
// Container 協(xié)議的實現(xiàn)部分
typealias ItemType = Int
mutating func append(item: Int) {
self.push(item)
}
var count: Int {
return items.count
}
subscript(i: Int) -> Int {
return items[i]
}
}
Where 子句
類型約束讓你能夠為泛型函數(shù)或泛型類型的類型參數(shù)定義一些強制要求。
func allItemsMatch<
C1: Container, C2: Container
where C1.ItemType == C2.ItemType, C1.ItemType: Equatable>
(someContainer: C1, _ anotherContainer: C2) -> Bool {
// 檢查兩個容器含有相同數(shù)量的元素
if someContainer.count != anotherContainer.count {
return false
}
// 檢查每一對元素是否相等
for i in 0..<someContainer.count {
if someContainer[i] != anotherContainer[i] {
return false
}
}
// 所有元素都匹配,返回 true
return true
}