Swift 泛型
Swift 提供了泛型讓你寫(xiě)出靈活且可重用的函數(shù)和類型。
Swift 標(biāo)準(zhǔn)庫(kù)是通過(guò)泛型代碼構(gòu)建出來(lái)的。
Swift 的數(shù)組和字典類型都是泛型集。
你可以創(chuàng)建一個(gè)Int數(shù)組,也可創(chuàng)建一個(gè)String數(shù)組,或者甚至于可以是任何其他 Swift 的類型數(shù)據(jù)數(shù)組。
以下實(shí)例是一個(gè)非泛型函數(shù) exchange 用來(lái)交換兩個(gè) Int 值:
// 定義一個(gè)交換兩個(gè)變量的函數(shù) func exchange(inout a: Int, inout b: Int) { let temp = a a = b b = temp } var numb1 = 100 var numb2 = 200 print("交換前數(shù)據(jù): \(numb1) 和 \(numb2)") exchange(&numb1, b: &numb2) print("交換后數(shù)據(jù): \(numb1) 和 \(numb2)")
以上程序執(zhí)行輸出結(jié)果為:
交換前數(shù)據(jù): 100 和 200 交換后數(shù)據(jù): 200 和 100
泛型函數(shù)可以訪問(wèn)任何類型,如 Int 或 String。
以下實(shí)例是一個(gè)泛型函數(shù) exchange 用來(lái)交換兩個(gè) Int 和 String 值:
func exchange<T>(inout a: T, inout b: T) { let temp = a a = b b = temp } var numb1 = 100 var numb2 = 200 print("交換前數(shù)據(jù): \(numb1) 和 \(numb2)") exchange(&numb1, b: &numb2) print("交換后數(shù)據(jù): \(numb1) 和 \(numb2)") var str1 = "A" var str2 = "B" print("交換前數(shù)據(jù): \(str1) 和 \(str2)") exchange(&str1, b: &str2) print("交換后數(shù)據(jù): \(str1) 和 \(str2)")
以上程序執(zhí)行輸出結(jié)果為:
交換前數(shù)據(jù): 100 和 200 交換后數(shù)據(jù): 200 和 100 交換前數(shù)據(jù): A 和 B 交換后數(shù)據(jù): B 和 A
這個(gè)函數(shù)的泛型版本使用了占位類型名字(通常此情況下用字母T來(lái)表示)來(lái)代替實(shí)際類型名(如Int、String或Double)。占位類型名沒(méi)有提示T必須是什么類型,但是它提示了a和b必須是同一類型T,而不管T表示什么類型。只有 exchange(_:_:)函數(shù)在每次調(diào)用時(shí)所傳入的實(shí)際類型才能決定T所代表的類型。
另外一個(gè)不同之處在于這個(gè)泛型函數(shù)名后面跟著的占位類型名字(T)是用尖括號(hào)括起來(lái)的()。這個(gè)尖括號(hào)告訴 Swift 那個(gè)T是 exchange(_:_:)函數(shù)所定義的一個(gè)類型。因?yàn)門(mén)是一個(gè)占位命名類型,Swift 不會(huì)去查找命名為T(mén)的實(shí)際類型。
泛型類型
Swift 允許你定義你自己的泛型類型。
自定義類、結(jié)構(gòu)體和枚舉作用于任何類型,如同Array和Dictionary的用法。
struct TOS<T> { var items = [T]() mutating func push(item: T) { items.append(item) } mutating func pop() -> T { return items.removeLast() } } var tos = TOS<String>() tos.push("Swift") print(tos.items) tos.push("泛型") print(tos.items) tos.push("類型參數(shù)") print(tos.items) tos.push("類型參數(shù)名") print(tos.items) let deletetos = tos.pop()
以上程序執(zhí)行輸出結(jié)果為:
["Swift"] ["Swift", "泛型"] ["Swift", "泛型", "類型參數(shù)"] ["Swift", "泛型", "類型參數(shù)", "類型參數(shù)名"]
擴(kuò)展泛型類型
當(dāng)你擴(kuò)展一個(gè)泛型類型的時(shí)候(使用 extension 關(guān)鍵字),你并不需要在擴(kuò)展的定義中提供類型參數(shù)列表。更加方便的是,原始類型定義中聲明的類型參數(shù)列表在擴(kuò)展里是可以使用的,并且這些來(lái)自原始類型中的參數(shù)名稱會(huì)被用作原始定義中類型參數(shù)的引用。
實(shí)例
下面的例子擴(kuò)展了泛型 TOS 類型,為其添加了一個(gè)名為 first 的只讀計(jì)算屬性,它將會(huì)返回當(dāng)前棧頂端的元素而不會(huì)將其從棧中移除。struct TOS<T> { var items = [T]() mutating func push(item: T) { items.append(item) } mutating func pop() -> T { return items.removeLast() } } var tos = TOS<String>() tos.push("Swift") print(tos.items) tos.push("泛型") print(tos.items) tos.push("類型參數(shù)") print(tos.items) tos.push("類型參數(shù)名") print(tos.items) // 擴(kuò)展泛型 TOS 類型 extension TOS { var first: T? { return items.isEmpty ? nil : items[items.count - 1] } } if let first = tos.first { print("棧頂部項(xiàng):\(first)") }
以上程序執(zhí)行輸出結(jié)果為:
["Swift"] ["Swift", "泛型"] ["Swift", "泛型", "類型參數(shù)"] ["Swift", "泛型", "類型參數(shù)", "類型參數(shù)名"] 棧頂部項(xiàng):類型參數(shù)名
類型約束
類型約束指定了一個(gè)必須繼承自指定類的類型參數(shù),或者遵循一個(gè)特定的協(xié)議或協(xié)議構(gòu)成。
類型約束語(yǔ)法
你可以寫(xiě)一個(gè)在一個(gè)類型參數(shù)名后面的類型約束,通過(guò)冒號(hào)分割,來(lái)作為類型參數(shù)鏈的一部分。這種作用于泛型函數(shù)的類型約束的基礎(chǔ)語(yǔ)法如下所示(和泛型類型的語(yǔ)法相同):
func someFunction<T: SomeClass, U: SomeProtocol>(someT: T, someU: U) { // 這里是函數(shù)主體 }
實(shí)例
// 函數(shù)可以作用于查找一字符串?dāng)?shù)組中的某個(gè)字符串 func findStringIndex(array: [String], _ valueToFind: String) -> Int? { for (index, value) in array.enumerate() { if value == valueToFind { return index } } return nil } let strings = ["cat", "dog", "llama", "parakeet", "terrapin"] if let foundIndex = findStringIndex(strings, "llama") { print("llama 的下標(biāo)索引值為 \(foundIndex)") }
以上程序執(zhí)行輸出結(jié)果為:
llama 的下標(biāo)索引值為 2
關(guān)聯(lián)類型實(shí)例
Swift 中使用 typealias 關(guān)鍵字來(lái)設(shè)置關(guān)聯(lián)類型。
定義一個(gè)協(xié)議時(shí),有的時(shí)候聲明一個(gè)或多個(gè)關(guān)聯(lián)類型作為協(xié)議定義的一部分是非常有用的。
protocol Container { // 定義了一個(gè)ItemType關(guān)聯(lián)類型 typealias ItemType mutating func append(item: ItemType) var count: Int { get } subscript(i: Int) -> ItemType { get } } // 遵循Container協(xié)議的泛型TOS類型 struct TOS<T>: Container { // original Stack<T> implementation var items = [T]() mutating func push(item: T) { items.append(item) } mutating func pop() -> T { return items.removeLast() } // conformance to the Container protocol mutating func append(item: T) { self.push(item) } var count: Int { return items.count } subscript(i: Int) -> T { return items[i] } } var tos = TOS<String>() tos.push("Swift") print(tos.items) tos.push("泛型") print(tos.items) tos.push("參數(shù)類型") print(tos.items) tos.push("類型參數(shù)名") print(tos.items)
以上程序執(zhí)行輸出結(jié)果為:
["Swift"] ["Swift", "泛型"] ["Swift", "泛型", "參數(shù)類型"] ["Swift", "泛型", "參數(shù)類型", "類型參數(shù)名"]
Where 語(yǔ)句
類型約束能夠確保類型符合泛型函數(shù)或類的定義約束。
你可以在參數(shù)列表中通過(guò)where語(yǔ)句定義參數(shù)的約束。
你可以寫(xiě)一個(gè)where語(yǔ)句,緊跟在在類型參數(shù)列表后面,where語(yǔ)句后跟一個(gè)或者多個(gè)針對(duì)關(guān)聯(lián)類型的約束,以及(或)一個(gè)或多個(gè)類型和關(guān)聯(lián)類型間的等價(jià)(equality)關(guān)系。
實(shí)例
下面的例子定義了一個(gè)名為allItemsMatch的泛型函數(shù),用來(lái)檢查兩個(gè)Container實(shí)例是否包含相同順序的相同元素。
如果所有的元素能夠匹配,那么返回一個(gè)為true的Boolean值,反之則為false。
protocol Container { typealias ItemType mutating func append(item: ItemType) var count: Int { get } subscript(i: Int) -> ItemType { get } } struct Stack<T>: Container { // original Stack<T> implementation var items = [T]() mutating func push(item: T) { items.append(item) } mutating func pop() -> T { return items.removeLast() } // conformance to the Container protocol mutating func append(item: T) { self.push(item) } var count: Int { return items.count } subscript(i: Int) -> T { return items[i] } } func allItemsMatch< C1: Container, C2: Container where C1.ItemType == C2.ItemType, C1.ItemType: Equatable> (someContainer: C1, anotherContainer: C2) -> Bool { // 檢查兩個(gè)Container的元素個(gè)數(shù)是否相同 if someContainer.count != anotherContainer.count { return false } // 檢查兩個(gè)Container相應(yīng)位置的元素彼此是否相等 for i in 0..<someContainer.count { if someContainer[i] != anotherContainer[i] { return false } } // 匹配所有項(xiàng),返回 true return true } var tos = Stack<String>() tos.push("Swift") print(tos.items) tos.push("泛型") print(tos.items) tos.push("Where 語(yǔ)句") print(tos.items) var eos = ["Swift", "泛型", "Where 語(yǔ)句"] print(eos)
以上程序執(zhí)行輸出結(jié)果為:
["Swift"] ["Swift", "泛型"] ["Swift", "泛型", "Where 語(yǔ)句"] ["Swift", "泛型", "Where 語(yǔ)句"]
更多建議: