淺談 Swift 中的泛型

作者:Thomas Hanning燎窘,原文鏈接,原文日期:2015/09/09
譯者:pmst蹄咖;校對:numbbbbb褐健;定稿:shanks

Objective-C缺乏一個重要特性:不支持泛型。幸運地是澜汤,Swift擁有這一特性蚜迅。泛型允許你聲明的函數(shù)、類以及結(jié)構(gòu)體支持不同的數(shù)據(jù)類型俊抵。

提出問題

優(yōu)秀的泛型使用案例中谁不,最常見的例子當(dāng)屬對棧(Stack)的操作。棧作為容器有兩種操作:一.壓入(Push)操作添加項到容器中;二.彈出(Pop)操作將最近添加項從容器移除徽诲。首先我們用非泛型方式設(shè)計刹帕。最后代碼如下所示:

class IntStack{
    // 采用數(shù)組作為容器保存數(shù)據(jù) 類型為Int
    private var stackItems:[Int] = []
    // 入棧操作 即Push 添加最新數(shù)據(jù)到容器最頂部
    func pushItem(item:Int){
        stackItems.append(item) 
    }
    // 出棧操作 即Pop 將容器最頂部數(shù)據(jù)移除
    func popItem()->Int?{
        let lastItem = stackItems.last
        stackItems.removeLast()
        return lastItem
    }
}

該棧能夠處理Int類型數(shù)據(jù)。這看起來不錯谎替,但是倘若要建立一個能夠處理String類型的偷溺,我們又該如何實現(xiàn)呢?我們需要替換所有IntString钱贯,不過這顯然是一個糟糕的解決方法挫掏。此外另外一種方法乍看之下灰常不錯,如下:

class AnyObjectStack{
    // 采用數(shù)組作為容器保存數(shù)據(jù) 類型為AnyObject
    private var stackItems:[AnyObject] = []
    // 入棧操作 即Push 添加最新數(shù)據(jù)到容器最頂部
    func pushItem(item:AnyObject){
        stackItems.append(item) 
    }
    // 出棧操作 即Pop 將容器最頂部數(shù)據(jù)移除
    func popItem()->AnyObject?{
        let lastItem = stackItems.last
        stackItems.removeLast()
        return lastItem
    }   
}

此處秩命,我們合理地使用AnyObject類型尉共,那么現(xiàn)在能夠?qū)?code>String類型數(shù)據(jù)壓入到棧中了,對么硫麻?不過這種情況下我們就失去了數(shù)據(jù)類型的安全爸邢,并且每當(dāng)我們對棧進行操作時,都需要進行一系列繁瑣的類型轉(zhuǎn)換(casting操作,使用as來進行類型轉(zhuǎn)換)。

解決方案

參照泛型的特性拿愧,我們能夠定義一個泛型類型杠河,這看起來像一個占位符。使用泛型后的示例代碼如下:

class Stack<T> {

    private var stackItems: [T] = []

    func pushItem(item:T) {
        stackItems.append(item)
    }

    func popItem() -> T? {
        let lastItem = stackItems.last
        stackItems.removeLast()
        return lastItem
    }

}

泛型定義方式:由一對尖括號(<>)包裹浇辜,命名方式通常為大寫字母開頭(這里我們命名為T)券敌。在初始化階段,我們通過明確的類型(這里為Int)來定義參數(shù),之后編譯器將所有的泛型T替換成Int類型:

// 指定了泛型T 就是 Int 
// 編譯器會替換所有T為Int
let aStack = Stack<Int>()

aStack.pushItem(10)
if let lastItem = aStack.popItem() {
    print("last item: \(lastItem)")
}

如此實現(xiàn)的棧柳洋,最大優(yōu)勢在于能夠匹配任何類型待诅。

類型約束

這里存在一個缺點:盡管泛型能夠代表任何類型,我們對它的操作也是比較有局限性的熊镣。僅僅是比較兩個泛型都是不支持的卑雁,請看如下代碼:

class Stack<T> {

    private var stackItems: [T] = []

    func pushItem(item:T) {
        stackItems.append(item)
    }

    func popItem() -> T? {
        let lastItem = stackItems.last
        stackItems.removeLast()
        return lastItem
    }

    func isItemInStack(item:T) -> Bool {
        var found = false
        for stackItem in stackItems {
            if stackItem == item { //編譯報錯!!!!!!!!!!
                found = true
            }
        }
        return found
    }
}

注意到函數(shù)isItemInSatck(item:T)中募书,我們得到了一個編譯錯誤,因為兩個參數(shù)沒有實現(xiàn)Equtable協(xié)議的話测蹲,類型值是不能進行比較的莹捡。實際上我們可以為泛型增加約束條件來解決這個問題。在本例中扣甲,通過對第一行進行修改篮赢,我們讓泛型T遵循Equatable協(xié)議:

class Stack<T:Equatable> {

    private var stackItems: [T] = []

    func pushItem(item:T) {
        stackItems.append(item)
    }

    func popItem() -> T? {
        let lastItem = stackItems.last
        stackItems.removeLast()
        return lastItem
    }

    func isItemInStack(item:T) -> Bool {
        var found = false
        for stackItem in stackItems {
            if stackItem == item {
                found = true
            }
        }
        return found
    }
}

總結(jié)

就像眾多其他編程語言一樣,你也能夠在Swift中利用泛型這一特性琉挖。倘若你想要寫一個庫启泣,泛型是非常好用的特性。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末示辈,一起剝皮案震驚了整個濱河市寥茫,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌顽耳,老刑警劉巖坠敷,帶你破解...
    沈念sama閱讀 222,252評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異射富,居然都是意外死亡,警方通過查閱死者的電腦和手機粥帚,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,886評論 3 399
  • 文/潘曉璐 我一進店門胰耗,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人芒涡,你說我怎么就攤上這事柴灯。” “怎么了费尽?”我有些...
    開封第一講書人閱讀 168,814評論 0 361
  • 文/不壞的土叔 我叫張陵赠群,是天一觀的道長。 經(jīng)常有香客問我旱幼,道長查描,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,869評論 1 299
  • 正文 為了忘掉前任柏卤,我火速辦了婚禮冬三,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘缘缚。我一直安慰自己勾笆,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 68,888評論 6 398
  • 文/花漫 我一把揭開白布桥滨。 她就那樣靜靜地躺著窝爪,像睡著了一般弛车。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上蒲每,一...
    開封第一講書人閱讀 52,475評論 1 312
  • 那天纷跛,我揣著相機與錄音,去河邊找鬼啃勉。 笑死忽舟,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的淮阐。 我是一名探鬼主播叮阅,決...
    沈念sama閱讀 41,010評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼泣特!你這毒婦竟也來了浩姥?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,924評論 0 277
  • 序言:老撾萬榮一對情侶失蹤状您,失蹤者是張志新(化名)和其女友劉穎勒叠,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體膏孟,經(jīng)...
    沈念sama閱讀 46,469評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡眯分,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,552評論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了柒桑。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片弊决。...
    茶點故事閱讀 40,680評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖魁淳,靈堂內(nèi)的尸體忽然破棺而出飘诗,到底是詐尸還是另有隱情,我是刑警寧澤界逛,帶...
    沈念sama閱讀 36,362評論 5 351
  • 正文 年R本政府宣布昆稿,位于F島的核電站,受9級特大地震影響息拜,放射性物質(zhì)發(fā)生泄漏溉潭。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 42,037評論 3 335
  • 文/蒙蒙 一该溯、第九天 我趴在偏房一處隱蔽的房頂上張望岛抄。 院中可真熱鬧,春花似錦狈茉、人聲如沸夫椭。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,519評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蹭秋。三九已至扰付,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間仁讨,已是汗流浹背羽莺。 一陣腳步聲響...
    開封第一講書人閱讀 33,621評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留洞豁,地道東北人盐固。 一個月前我還...
    沈念sama閱讀 49,099評論 3 378
  • 正文 我出身青樓,卻偏偏與公主長得像丈挟,于是被迫代替她去往敵國和親刁卜。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,691評論 2 361

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

  • 本章將會介紹 泛型所解決的問題泛型函數(shù)類型參數(shù)命名類型參數(shù)泛型類型擴展一個泛型類型類型約束關(guān)聯(lián)類型泛型 Where...
    寒橋閱讀 640評論 0 2
  • 泛型代碼可以確保你寫出靈活的曙咽,可重用的函數(shù)和定義出任何你所確定好的需求的類型蛔趴。你的可以寫出避免重復(fù)的代碼,并且用一...
    iOS_Developer閱讀 803評論 0 0
  • importUIKit classViewController:UITabBarController{ enumD...
    明哥_Young閱讀 3,819評論 1 10
  • 如果可以選擇例朱,我渴望主動孝情。 在做很多事情的時候,我們都需要預(yù)先做準備洒嗤,因為被動和主動的是不一樣的箫荡。而且差別很大,我...
    盧桂林閱讀 301評論 0 0
  • 未有先知渔隶,何來悔恨 原來多做幾次就會習(xí)慣 那有什么煩亂 言語延續(xù)的是單調(diào)的變換 飛過頭頂?shù)娘w機時間太短 沒有霓虹的...
    FTHEG閱讀 341評論 0 0