淺談 Swift 中的泛型

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

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

提出問題

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

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ù)。這看起來不錯(cuò),但是倘若要建立一個(gè)能夠處理String類型的,我們又該如何實(shí)現(xiàn)呢?我們需要替換所有IntString,不過這顯然是一個(gè)糟糕的解決方法。此外另外一種方法乍看之下灰常不錯(cuò),如下:

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)我們對棧進(jìn)行操作時(shí),都需要進(jìn)行一系列繁瑣的類型轉(zhuǎn)換(casting操作,使用as來進(jìn)行類型轉(zhuǎn)換)。

解決方案

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

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 
// 編譯器會(huì)替換所有T為Int
let aStack = Stack<Int>()

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

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

類型約束

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

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 { //編譯報(bào)錯(cuò)!!!!!!!!!!
                found = true
            }
        }
        return found
    }
}

注意到函數(shù)isItemInSatck(item:T)中,我們得到了一個(gè)編譯錯(cuò)誤,因?yàn)閮蓚€(gè)參數(shù)沒有實(shí)現(xiàn)Equtable協(xié)議的話,類型值是不能進(jìn)行比較的。實(shí)際上我們可以為泛型增加約束條件來解決這個(gè)問題。在本例中,通過對第一行進(jìn)行修改,我們讓泛型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中利用泛型這一特性。倘若你想要寫一個(gè)庫,泛型是非常好用的特性。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

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

友情鏈接更多精彩內(nèi)容