Swift 泛型

Swift 提供了泛型讓你寫出靈活且可重用的函數(shù)和類型矫限。Swift 標準庫是通過泛型代碼構(gòu)建出來的催式。Swift 的數(shù)組和字典類型都是泛型集徽曲。你可以創(chuàng)建一個Int數(shù)組临庇,也可創(chuàng)建一個String數(shù)組反璃,或者甚至于可以是任何其他 Swift 的類型數(shù)據(jù)數(shù)組。以下實例是一個非泛型函數(shù) exchange 用來交換兩個 Int 值:實例// 定義一個交換兩個變量的函數(shù)func swapTwoInts(_ a: inout Int, _ b: inout Int) {? ? let temporaryA = a? ? a = b? ? b = temporaryA} var numb1 = 100var numb2 = 200 print("交換前數(shù)據(jù): \(numb1) 和 \(numb2)")swapTwoInts(&numb1, &numb2)print("交換后數(shù)據(jù): \(numb1) 和 \(numb2)")以上程序執(zhí)行輸出結(jié)果為:交換前數(shù)據(jù): 100 和 200交換后數(shù)據(jù): 200 和 100以上實例只試用與交換整數(shù) Int 類型的變量假夺。如果你想要交換兩個 String 值或者 Double 值淮蜈,就得重新寫個對應的函數(shù),例如 swapTwoStrings(_:_:) 和 swapTwoDoubles(_:_:)已卷,如下所示:String 和 Double 值交換函數(shù)func swapTwoStrings(_ a: inout String, _ b: inout String) {? ? let temporaryA = a? ? a = b? ? b = temporaryA} func swapTwoDoubles(_ a: inout Double, _ b: inout Double) {? ? let temporaryA = a? ? a = b? ? b = temporaryA}從以上代碼來看梧田,它們功能代碼是相同的,只是類型上不一樣,這時我們可以使用泛型裁眯,從而避免重復編寫代碼鹉梨。泛型使用了占位類型名(在這里用字母 T 來表示)來代替實際類型名(例如 Int、String 或 Double)穿稳。func swapTwoValues(_ a: inout T, _ b: inout T)swapTwoValues 后面跟著占位類型名(T)存皂,并用尖括號括起來()。這個尖括號告訴 Swift 那個 T 是 swapTwoValues(_:_:) 函數(shù)定義內(nèi)的一個占位類型名逢艘,因此 Swift 不會去查找名為 T 的實際類型旦袋。以下實例是一個泛型函數(shù) exchange 用來交換兩個 Int 和 String 值:實例// 定義一個交換兩個變量的函數(shù)func swapTwoValues(_ a: inout T, _ b: inout T) {? ? let temporaryA = a? ? a = b? ? b = temporaryA} var numb1 = 100var numb2 = 200 print("交換前數(shù)據(jù):? \(numb1) 和 \(numb2)")swapTwoValues(&numb1, &numb2)print("交換后數(shù)據(jù): \(numb1) 和 \(numb2)") var str1 = "A"var str2 = "B" print("交換前數(shù)據(jù):? \(str1) 和 \(str2)")swapTwoValues(&str1, &str2)print("交換后數(shù)據(jù): \(str1) 和 \(str2)")以上程序執(zhí)行輸出結(jié)果為:交換前數(shù)據(jù):? 100 和 200交換后數(shù)據(jù): 200 和 100交換前數(shù)據(jù):? A 和 B交換后數(shù)據(jù): B 和 A泛型類型Swift 允許你定義你自己的泛型類型。自定義類它改、結(jié)構(gòu)體和枚舉作用于任何類型疤孕,如同 Array 和 Dictionary 的用法。接下來我們來編寫一個名為 Stack (棧)的泛型集合類型央拖,棧只允許在集合的末端添加新的元素(稱之為入棧)祭阀,且也只能從末端移除元素(稱之為出棧)。圖片中從左到右解析如下:三個值在棧中爬泥。第四個值被壓入到棧的頂部〖硖郑現(xiàn)在有四個值在棧中崩瓤,最近入棧的那個值在頂部袍啡。棧中最頂部的那個值被移除,或稱之為出棧却桶。移除掉一個值后境输,現(xiàn)在棧又只有三個值了。以下實例是一個非泛型版本的棧颖系,以 Int 型的棧為例:Int 型的棧struct IntStack {? ? var items = [Int]()? ? mutating func push(_ item: Int) {? ? ? ? items.append(item)? ? }? ? mutating func pop() -> Int {? ? ? ? return items.removeLast()? ? }}這個結(jié)構(gòu)體在棧中使用一個名為 items 的 Array 屬性來存儲值嗅剖。Stack 提供了兩個方法:push(_:) 和 pop(),用來向棧中壓入值以及從棧中移除值嘁扼。這些方法被標記為 mutating信粮,因為它們需要修改結(jié)構(gòu)體的 items 數(shù)組。上面的 IntStack 結(jié)構(gòu)體只能用于 Int 類型趁啸。不過强缘,可以定義一個泛型 Stack 結(jié)構(gòu)體,從而能夠處理任意類型的值不傅。下面是相同代碼的泛型版本:泛型的棧struct Stack{? ? var items = [Element]()? ? mutating func push(_ item: Element) {? ? ? ? items.append(item)? ? }? ? mutating func pop() -> Element {? ? ? ? return items.removeLast()? ? }} var stackOfStrings = Stack()print("字符串元素入棧: ")stackOfStrings.push("google")stackOfStrings.push("runoob")print(stackOfStrings.items); let deletetos = stackOfStrings.pop()print("出棧元素: " + deletetos) var stackOfInts = Stack()print("整數(shù)元素入棧: ")stackOfInts.push(1)stackOfInts.push(2)print(stackOfInts.items);實例執(zhí)行結(jié)果為:字符串元素入棧: ["google", "runoob"]出棧元素: runoob整數(shù)元素入棧: [1, 2]Stack 基本上和 IntStack 相同旅掂,占位類型參數(shù) Element 代替了實際的 Int 類型。以上實例中 Element 在如下三個地方被用作占位符:創(chuàng)建 items 屬性访娶,使用 Element 類型的空數(shù)組對其進行初始化商虐。指定 push(_:) 方法的唯一參數(shù) item 的類型必須是 Element 類型。指定 pop() 方法的返回值類型必須是 Element 類型。擴展泛型類型當你擴展一個泛型類型的時候(使用 extension 關(guān)鍵字)秘车,你并不需要在擴展的定義中提供類型參數(shù)列表典勇。更加方便的是,原始類型定義中聲明的類型參數(shù)列表在擴展里是可以使用的叮趴,并且這些來自原始類型中的參數(shù)名稱會被用作原始定義中類型參數(shù)的引用痴柔。下面的例子擴展了泛型類型 Stack,為其添加了一個名為 topItem 的只讀計算型屬性疫向,它將會返回當前棧頂端的元素而不會將其從棧中移除:泛型struct Stack{? ? var items = [Element]()? ? mutating func push(_ item: Element) {? ? ? ? items.append(item)? ? }? ? mutating func pop() -> Element {? ? ? ? return items.removeLast()? ? }} extension Stack {? ? var topItem: Element? {? ? ? return items.isEmpty ? nil : items[items.count - 1]? ? }} var stackOfStrings = Stack()print("字符串元素入棧: ")stackOfStrings.push("google")stackOfStrings.push("runoob") if let topItem = stackOfStrings.topItem {? ? print("棧中的頂部元素是:\(topItem).")} print(stackOfStrings.items)實例中 topItem 屬性會返回一個 Element 類型的可選值咳蔚。當棧為空的時候,topItem 會返回 nil搔驼;當棧不為空的時候谈火,topItem 會返回 items 數(shù)組中的最后一個元素。以上程序執(zhí)行輸出結(jié)果為:字符串元素入棧: 棧中的頂部元素是:runoob.["google", "runoob"]我們也可以通過擴展一個存在的類型來指定關(guān)聯(lián)類型舌涨。例如 Swift 的 Array 類型已經(jīng)提供 append(_:) 方法糯耍,一個 count 屬性,以及一個接受 Int 類型索引值的下標用以檢索其元素囊嘉。這三個功能都符合 Container 協(xié)議的要求温技,所以你只需簡單地聲明 Array 采納該協(xié)議就可以擴展 Array。以下實例創(chuàng)建一個空擴展即可:extension Array: Container {}類型約束類型約束指定了一個必須繼承自指定類的類型參數(shù)扭粱,或者遵循一個特定的協(xié)議或協(xié)議構(gòu)成舵鳞。類型約束語法你可以寫一個在一個類型參數(shù)名后面的類型約束,通過冒號分割琢蛤,來作為類型參數(shù)鏈的一部分蜓堕。這種作用于泛型函數(shù)的類型約束的基礎語法如下所示(和泛型類型的語法相同):func someFunction(someT: T, someU: U) {? ? // 這里是泛型函數(shù)的函數(shù)體部分}上面這個函數(shù)有兩個類型參數(shù)。第一個類型參數(shù) T博其,有一個要求 T 必須是 SomeClass 子類的類型約束套才;第二個類型參數(shù) U,有一個要求 U 必須符合 SomeProtocol 協(xié)議的類型約束慕淡。實例泛型// 非泛型函數(shù)背伴,查找指定字符串在數(shù)組中的索引func findIndex(ofString valueToFind: String, in array: [String]) -> Int? {? ? for (index, value) in array.enumerated() {? ? ? ? if value == valueToFind {? ? ? ? ? ? // 找到返回索引值? ? ? ? ? ? return index? ? ? ? }? ? }? ? return nil}? let strings = ["google", "weibo", "taobao", "runoob", "facebook"]if let foundIndex = findIndex(ofString: "runoob", in: strings) {? ? print("runoob 的索引為 \(foundIndex)")}索引下標從 0 開始。以上程序執(zhí)行輸出結(jié)果為:runoob 的索引為 3關(guān)聯(lián)類Swift 中使用 associatedtype 關(guān)鍵字來設置關(guān)聯(lián)類型實例峰髓。下面例子定義了一個 Container 協(xié)議傻寂,該協(xié)議定義了一個關(guān)聯(lián)類型 ItemType。Container 協(xié)議只指定了三個任何遵從 Container 協(xié)議的類型必須提供的功能儿普。遵從協(xié)議的類型在滿足這三個條件的情況下也可以提供其他額外的功能崎逃。// Container 協(xié)議protocol Container {? ? associatedtype ItemType? ? // 添加一個新元素到容器里? ? mutating func append(_ item: ItemType)? ? // 獲取容器中元素的數(shù)? ? var count: Int { get }? ? // 通過索引值類型為 Int 的下標檢索到容器中的每一個元素? ? subscript(i: Int) -> ItemType { get }}// Stack 結(jié)構(gòu)體遵從 Container 協(xié)議struct Stack: Container {? ? // Stack的原始實現(xiàn)部分? ? var items = [Element]()? ? mutating func push(_ item: Element) {? ? ? ? items.append(item)? ? }? ? mutating func pop() -> Element {? ? ? ? return items.removeLast()? ? }? ? // Container 協(xié)議的實現(xiàn)部分? ? mutating func append(_ item: Element) {? ? ? ? self.push(item)? ? }? ? var count: Int {? ? ? ? return items.count? ? }? ? subscript(i: Int) -> Element {? ? ? ? return items[i]? ? }}var tos = Stack()tos.push("google")tos.push("runoob")tos.push("taobao")// 元素列表print(tos.items)// 元素個數(shù)print( tos.count)以上程序執(zhí)行輸出結(jié)果為:["google", "runoob", "taobao"]3Where 語句類型約束能夠確保類型符合泛型函數(shù)或類的定義約束。你可以在參數(shù)列表中通過where語句定義參數(shù)的約束眉孩。你可以寫一個where語句个绍,緊跟在在類型參數(shù)列表后面勒葱,where語句后跟一個或者多個針對關(guān)聯(lián)類型的約束,以及(或)一個或多個類型和關(guān)聯(lián)類型間的等價(equality)關(guān)系巴柿。實例下面的例子定義了一個名為allItemsMatch的泛型函數(shù)凛虽,用來檢查兩個Container實例是否包含相同順序的相同元素。如果所有的元素能夠匹配广恢,那么返回 true凯旋,反之則返回 false。泛型// Container 協(xié)議protocol Container {? ? associatedtype ItemType? ? // 添加一個新元素到容器里? ? mutating func append(_ item: ItemType)? ? // 獲取容器中元素的數(shù)? ? var count: Int { get }? ? // 通過索引值類型為 Int 的下標檢索到容器中的每一個元素? ? subscript(i: Int) -> ItemType { get }} // // 遵循Container協(xié)議的泛型TOS類型struct Stack: Container {? ? // Stack的原始實現(xiàn)部分? ? var items = [Element]()? ? mutating func push(_ item: Element) {? ? ? ? items.append(item)? ? }? ? mutating func pop() -> Element {? ? ? ? return items.removeLast()? ? }? ? // Container 協(xié)議的實現(xiàn)部分? ? mutating func append(_ item: Element) {? ? ? ? self.push(item)? ? }? ? var count: Int {? ? ? ? return items.count? ? }? ? subscript(i: Int) -> Element {? ? ? ? return items[i]? ? }}// 擴展钉迷,將 Array 當作 Container 來使用extension Array: Container {} func allItemsMatch(_ someContainer: C1, _ anotherContainer: C2) -> Bool? ? where C1.ItemType == C2.ItemType, C1.ItemType: Equatable {? ? ? ? ? ? ? ? // 檢查兩個容器含有相同數(shù)量的元素? ? ? ? if someContainer.count != anotherContainer.count {? ? ? ? ? ? return false? ? ? ? }? ? ? ? ? ? ? ? // 檢查每一對元素是否相等? ? ? ? for i in 0..()

tos.push("google")

tos.push("runoob")

tos.push("taobao")

var aos = ["google", "runoob", "taobao"]

if allItemsMatch(tos, aos) {

print("匹配所有元素")

} else {

print("元素不匹配")

}

以上程序執(zhí)行輸出結(jié)果為:

匹配所有元素

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末至非,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子糠聪,更是在濱河造成了極大的恐慌荒椭,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,590評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件舰蟆,死亡現(xiàn)場離奇詭異趣惠,居然都是意外死亡,警方通過查閱死者的電腦和手機身害,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,157評論 3 399
  • 文/潘曉璐 我一進店門味悄,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人塌鸯,你說我怎么就攤上這事侍瑟。” “怎么了界赔?”我有些...
    開封第一講書人閱讀 169,301評論 0 362
  • 文/不壞的土叔 我叫張陵丢习,是天一觀的道長。 經(jīng)常有香客問我淮悼,道長,這世上最難降的妖魔是什么揽思? 我笑而不...
    開封第一講書人閱讀 60,078評論 1 300
  • 正文 為了忘掉前任袜腥,我火速辦了婚禮,結(jié)果婚禮上钉汗,老公的妹妹穿的比我還像新娘羹令。我一直安慰自己,他們只是感情好损痰,可當我...
    茶點故事閱讀 69,082評論 6 398
  • 文/花漫 我一把揭開白布福侈。 她就那樣靜靜地躺著,像睡著了一般卢未。 火紅的嫁衣襯著肌膚如雪肪凛。 梳的紋絲不亂的頭發(fā)上堰汉,一...
    開封第一講書人閱讀 52,682評論 1 312
  • 那天,我揣著相機與錄音伟墙,去河邊找鬼翘鸭。 笑死,一個胖子當著我的面吹牛戳葵,可吹牛的內(nèi)容都是我干的就乓。 我是一名探鬼主播,決...
    沈念sama閱讀 41,155評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼拱烁,長吁一口氣:“原來是場噩夢啊……” “哼生蚁!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起戏自,我...
    開封第一講書人閱讀 40,098評論 0 277
  • 序言:老撾萬榮一對情侶失蹤守伸,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后浦妄,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體尼摹,經(jīng)...
    沈念sama閱讀 46,638評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,701評論 3 342
  • 正文 我和宋清朗相戀三年剂娄,在試婚紗的時候發(fā)現(xiàn)自己被綠了蠢涝。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,852評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡阅懦,死狀恐怖和二,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情耳胎,我是刑警寧澤惯吕,帶...
    沈念sama閱讀 36,520評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站怕午,受9級特大地震影響废登,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜郁惜,卻給世界環(huán)境...
    茶點故事閱讀 42,181評論 3 335
  • 文/蒙蒙 一堡距、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧兆蕉,春花似錦羽戒、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,674評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至包蓝,卻和暖如春驶社,著一層夾襖步出監(jiān)牢的瞬間企量,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,788評論 1 274
  • 我被黑心中介騙來泰國打工衬吆, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留梁钾,地道東北人。 一個月前我還...
    沈念sama閱讀 49,279評論 3 379
  • 正文 我出身青樓逊抡,卻偏偏與公主長得像姆泻,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子冒嫡,可洞房花燭夜當晚...
    茶點故事閱讀 45,851評論 2 361

推薦閱讀更多精彩內(nèi)容

  • 泛型代碼可以確保你寫出靈活的拇勃,可重用的函數(shù)和定義出任何你所確定好的需求的類型。你的可以寫出避免重復的代碼孝凌,并且用一...
    iOS_Developer閱讀 803評論 0 0
  • 136.泛型 泛型代碼讓你可以寫出靈活,可重用的函數(shù)和類型,它們可以使用任何類型,受你定義的需求的約束方咆。你可以寫出...
    無灃閱讀 1,480評論 0 4
  • 附上Apple文檔翻譯版 1.為什么需要泛型的使用 其實說白了很簡單。就是對于方法結(jié)構(gòu)相同蟀架,但是由于類型不同瓣赂,而需...
    mdiep閱讀 322評論 0 4
  • 本文轉(zhuǎn)載自http://blog.csdn.net/youshaoduo/article/details/5486...
    desunire閱讀 1,935評論 0 0
  • 天空晴朗,無云片拍。北風略過煌集,仿佛再無纖塵,水洗般的清澈捌省,潔純苫纤。真心何時可以如同這天空般,盡管冰寒纲缓,卻無太多負擔卷拘,只撒...
    暮雨激潭閱讀 212評論 1 2