Swift泛型

前言

OC缺乏一個(gè)重要特性,不支持泛型峭拘。Swift擁有了這一特性俊庇,是靈活性的語法狮暑,在函數(shù)、結(jié)構(gòu)體辉饱、類搬男、枚舉中都可以應(yīng)用,相當(dāng)于暫位符的作用彭沼,當(dāng)類型暫時(shí)不確定缔逛,只有等到調(diào)用函數(shù)時(shí)才能確定具體類型的時(shí)候可以引入泛型。

簡(jiǎn)單理解泛型就是先占位姓惑,具體占位做什么褐奴,用的時(shí)候再說。Swift的Array和Dictionary類型都是泛型集

應(yīng)用場(chǎng)景

簡(jiǎn)單模仿一個(gè)棧操作于毙,主要實(shí)現(xiàn)出棧敦冬、入棧兩個(gè)功能

// MARK: - 模仿棧
class TestStack {
    var valueArray: [Int] = []
    
    /// 壓棧
    func push(value: Int) -> () {
        valueArray.append(value)
    }
    
    /// 出棧
    func pop() -> (Int?) {
        if let lastValue = valueArray.last {
            valueArray.removeLast()
            return lastValue
            
        }else {
            return nil
        }
    }
}

這樣實(shí)現(xiàn)的棧只能操作Int類型,如果需求變更唯沮,要處理String類型匪补,怎么解決?替換所有Int為String可以解決烂翰,但這種代碼明顯上不了臺(tái)面。此外另外我們還會(huì)想到Any類型蚤氏,如下

// MARK: - 模仿棧
class TestStack {
    var valueArray: [Any] = []
    
    /// 壓棧
    func push(value: Any) -> () {
        valueArray.append(value)
    }
    
    /// 出棧
    func pop() -> (Any?) {
        if let lastValue = valueArray.last {
            valueArray.removeLast()
            return lastValue
            
        }else {
            return nil
        }
    }
}

如此TestStack可操作類型就不局限于一種了甘耿,但是帶來了兩個(gè)問題:1、數(shù)據(jù)類型安全問題竿滨;2佳恬、每次對(duì)棧進(jìn)行操作時(shí),都需要進(jìn)行一系列繁瑣的類型轉(zhuǎn)換(casting操作于游,使用as來進(jìn)行類型轉(zhuǎn)換)

這里簡(jiǎn)單介紹下Any和AnyObject的區(qū)別:

在 Swift 3 之前毁葱,我們可以寫完一個(gè)項(xiàng)目都只用 AnyObject 來代表大多數(shù)實(shí)例,好像不用與 Any 類型打交道贰剥。但事實(shí)上倾剿,Any 和 AnyObject 是有明顯區(qū)別的,因?yàn)?Any 可以代表 struct蚌成、class前痘、func 等等幾乎所有類型,而 AnyObject 只能代表 class 生成的實(shí)例担忧。

那為什么之前我們?cè)?Swift 2 里可以用 [AnyObject] 聲明數(shù)組芹缔,并且在里面放 Int、String 等 struct 類型呢瓶盛?這是因?yàn)?Swift 2 中最欠,會(huì)針對(duì)這些 Int示罗、String 等 struct 進(jìn)行一個(gè) Implicit Bridging Conversions,在 Array 里插入他們時(shí)芝硬,編譯器會(huì)自動(dòng)將其 bridge 到 Objective-C 的 NSNumber蚜点、NSString 等類型,這就是為什么我們聲明的 [AnyObject] 里可以放 struct 的原因吵取。

但在 Swift 3 當(dāng)中禽额,為了達(dá)成一個(gè)門真正的跨平臺(tái)語言,相關(guān)提案將 Implicit Bridging Conversions 給去掉了皮官。所以如果你要把 String 這個(gè) struct 放進(jìn)一個(gè) [AnyObject] 里脯倒,一定要 as NSString,這些轉(zhuǎn)換都需要顯示的進(jìn)行了——畢竟 Linux 平臺(tái)默認(rèn)沒有 Objective-C runtime捺氢。這樣各平臺(tái)的表現(xiàn)更加一致藻丢。當(dāng)然這是其中一個(gè)目標(biāo)。

參照泛型的特性摄乒,定義一個(gè)泛型類型悠反。使用泛型后的示例代碼如下:
`
// MARK: - 模仿棧
class TestStack<T> {
var valueArray: [T] = []

/// 壓棧
func push(value: T) -> () {
    valueArray.append(value)
}

/// 出棧
func pop() -> (T?) {
    if let lastValue = valueArray.last {
        valueArray.removeLast()
        return lastValue
        
    }else {
        return nil
    }
}

}
`

使用泛型:在初始化時(shí)通過明確的類型(這里用Int示例)來定義參數(shù),之后編譯器會(huì)將所有的泛型(T)替換成Int類型(如此實(shí)現(xiàn)的棧馍佑,最大優(yōu)勢(shì)在于能夠匹配任何類型)斋否。

       // 示例1:Int
        let myStack1 = TestStack<Int>()
        myStack1.push(value: 1)
        myStack1.push(value: 2)
        myStack1.push(value: 3)
        print(myStack1.pop() ?? "0")
        
        // 示例2:String
        let myStack2 = TestStack<String>()
        myStack2.push(value: "a")
        myStack2.push(value: "b")
        myStack2.push(value: "c")
        print(myStack2.pop() ?? "0")

泛型約束

泛型約束大致分為以下幾種:

協(xié)議約束,泛型類型必須遵循某些協(xié)議
繼承約束拭荤,泛型類型必須是某個(gè)類的子類類型
條件約束茵臭,泛型類型必須滿足某種條件

協(xié)議約束

還拿TestStack棧說事兒,這里添加一個(gè)函數(shù)isContainValue舅世,要判斷棧中是否包含傳入的元素旦委,需要用到等式符(==)和不等符(!=)對(duì)任何兩個(gè)該類型進(jìn)行比較。Swift標(biāo)準(zhǔn)庫(kù)中定義了一個(gè)Equatable協(xié)議雏亚,只有支持了這個(gè)協(xié)議才可以使用等式符(==)和不等符(!=)缨硝,否則報(bào)紅。所有的Swift標(biāo)準(zhǔn)類型自動(dòng)支持Equatable協(xié)議罢低,但是泛型由于不確定類型查辩,系統(tǒng)不知對(duì)象是否支持Equatable協(xié)議,所以直接使用==或!=報(bào)紅


泛型協(xié)議約束.png

解決方案网持,讓TestStack棧中宜肉,讓泛型T遵循Equatable協(xié)議


泛型協(xié)議約束1.png
繼承約束

這里定義了三個(gè)類Person、Leader翎碑、Coder谬返,其中Leader是繼承Person,

// MARK: - 人
class Person: NSObject {
    func watchTV() -> () {
        print("Person看電視:人民的名義")
    }
}


// MARK: - 領(lǐng)導(dǎo)
class Leader: Person {
    override func watchTV() -> () {
        print("Leader看電視:人民的名義")
    }
}


// MARK: - 程序員
class Coder {
    func watchTV() -> () {
        print("coder看電視:人民的名義")
    }
}
泛型繼承約束1.png
    func testWatchTV<T: Person>(obj:T) -> () {
        obj.watchTV()
    }

testWatchTV函數(shù),接受一個(gè)泛型參數(shù)日杈,要求該泛型類型必須繼承Person遣铝,否則爆紅佑刷。

條件約束

在類型名后面使用where來指定對(duì)類型的特殊需求,比如限定類型實(shí)現(xiàn)某一個(gè)協(xié)議酿炸,限定兩個(gè)類型是相同的瘫絮,或者限定某個(gè)類必須有一個(gè)特定的父類等

// 定義一個(gè)協(xié)議
@objc protocol TestProtocol {
    @objc optional func testOne() -> ()
}

// MARK: - 人
class Person: NSObject, TestProtocol {
    var name: String?
    
    func watchTV() -> () {
        print("Person看電視:人民的名義")
    }
}


// MARK: - 領(lǐng)導(dǎo)
class Leader: NSObject {
    var name: String?
    
    func watchTV() -> () {
        print("Leader看電視:人民的名義")
    }
}
泛型條件約束1.png

testCondition函數(shù)要求傳入的參數(shù)都是P類型的繼承自Person,L類型繼承自Leader填硕,同時(shí)還附加了條件(where)這兩個(gè)類都遵守了TestProtocol協(xié)議麦萤,由于Leader類型沒有遵守TestProtocol協(xié)議,條件不滿足所以爆紅扁眯。修改方法則是Leader類遵守TestProtocol壮莹。

參考鏈接:http://www.reibang.com/p/a907f0c09a60
參考鏈接:http://swift.gg/2015/09/16/swift-generics/

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市姻檀,隨后出現(xiàn)的幾起案子命满,更是在濱河造成了極大的恐慌,老刑警劉巖绣版,帶你破解...
    沈念sama閱讀 218,546評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件胶台,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡杂抽,警方通過查閱死者的電腦和手機(jī)诈唬,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,224評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來缩麸,“玉大人铸磅,你說我怎么就攤上這事〕锥茫” “怎么了?”我有些...
    開封第一講書人閱讀 164,911評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵济竹,是天一觀的道長(zhǎng)痕檬。 經(jīng)常有香客問我,道長(zhǎng)送浊,這世上最難降的妖魔是什么梦谜? 我笑而不...
    開封第一講書人閱讀 58,737評(píng)論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮袭景,結(jié)果婚禮上唁桩,老公的妹妹穿的比我還像新娘。我一直安慰自己耸棒,他們只是感情好荒澡,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,753評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著与殃,像睡著了一般单山。 火紅的嫁衣襯著肌膚如雪碍现。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,598評(píng)論 1 305
  • 那天米奸,我揣著相機(jī)與錄音昼接,去河邊找鬼。 笑死悴晰,一個(gè)胖子當(dāng)著我的面吹牛慢睡,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播铡溪,決...
    沈念sama閱讀 40,338評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼漂辐,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了佃却?” 一聲冷哼從身側(cè)響起者吁,我...
    開封第一講書人閱讀 39,249評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎饲帅,沒想到半個(gè)月后复凳,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,696評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡灶泵,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,888評(píng)論 3 336
  • 正文 我和宋清朗相戀三年育八,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片赦邻。...
    茶點(diǎn)故事閱讀 40,013評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡髓棋,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出惶洲,到底是詐尸還是另有隱情按声,我是刑警寧澤,帶...
    沈念sama閱讀 35,731評(píng)論 5 346
  • 正文 年R本政府宣布恬吕,位于F島的核電站签则,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏铐料。R本人自食惡果不足惜渐裂,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,348評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望钠惩。 院中可真熱鬧柒凉,春花似錦、人聲如沸篓跛。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,929評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽愧沟。三九已至绑警,卻和暖如春求泰,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背计盒。 一陣腳步聲響...
    開封第一講書人閱讀 33,048評(píng)論 1 270
  • 我被黑心中介騙來泰國(guó)打工渴频, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人北启。 一個(gè)月前我還...
    沈念sama閱讀 48,203評(píng)論 3 370
  • 正文 我出身青樓卜朗,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親咕村。 傳聞我的和親對(duì)象是個(gè)殘疾皇子场钉,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,960評(píng)論 2 355

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

  • 泛型代碼可以確保你寫出靈活的,可重用的函數(shù)和定義出任何你所確定好的需求的類型懈涛。你的可以寫出避免重復(fù)的代碼逛万,并且用一...
    iOS_Developer閱讀 800評(píng)論 0 0
  • 原文:Generics Manifesto -- Douglas Gregor 譯者注 在我慢慢地深入使用 Swi...
    kemchenj閱讀 1,987評(píng)論 0 6
  • Swift 提供了泛型讓你寫出靈活且可重用的函數(shù)和類型。Swift 標(biāo)準(zhǔn)庫(kù)是通過泛型代碼構(gòu)建出來的批钠。Swift 的...
    零度_不結(jié)冰閱讀 419評(píng)論 0 0
  • 本文轉(zhuǎn)載自http://blog.csdn.net/youshaoduo/article/details/5486...
    desunire閱讀 1,934評(píng)論 0 0
  • 附上Apple文檔翻譯版 1.為什么需要泛型的使用 其實(shí)說白了很簡(jiǎn)單宇植。就是對(duì)于方法結(jié)構(gòu)相同,但是由于類型不同埋心,而需...
    mdiep閱讀 320評(píng)論 0 4