Swift中Optional類型的使用案例分析:valuesForKeys

這篇文章將帶我們探索在Swift中如何使用Optional類型保證強(qiáng)類型的安全性愉择。我們將創(chuàng)建一個(gè)Swift版本的Objective-C的API印屁。雖然在Swift中這個(gè)API存在的意義不是很大锹淌,但是這將會(huì)是一個(gè)很有趣的例子刃鳄。

在Objective-C中配乓,NSDictionary類有一個(gè)方法,名為-objectsForKeys:notFoundMarker:,它的作用是根據(jù)第一NSArray類型參數(shù)中的值作為該字典的key,查找這些key對(duì)應(yīng)的字典中的值并放到一個(gè)新的NSArray中返回,如果找不到對(duì)應(yīng)的值汁咏,那么就返回第二個(gè)參數(shù)指定的對(duì)象。在官方文檔中對(duì)該方法有這么一句描述“返回的數(shù)組中的第N個(gè)對(duì)象作媚,對(duì)應(yīng)著第一個(gè)數(shù)組參數(shù)中的第N個(gè)值”攘滩。假如說(shuō)以第一個(gè)數(shù)組參數(shù)中的第三個(gè)值作為key在字典中查不到值怎么辦呢?這時(shí)候就需要notFoundMarker參數(shù)登場(chǎng)了纸泡。這種情況下就會(huì)返回notFoundMarker參數(shù)指定的對(duì)象了漂问。在Foundation框架中還有專門(mén)針對(duì)該情況適用的一個(gè)類,那就是NSNull,就是當(dāng)你也沒(méi)有備選返回對(duì)象的時(shí)候蚤假,就可以返回NSNull對(duì)象栏饮。

在Swift中,Dictionary類型并沒(méi)有類似objectsForKeys的方法磷仰。所以接下來(lái)的練習(xí)中袍嬉,我們將使用類型的擴(kuò)展機(jī)制為Dictionary類型添加一個(gè)類似objectsForKeys的方法,為保持Swift的風(fēng)格我們起名為valuesForKeys:notFoundMarker:灶平。

extension Dictionary { 
            func valuesForKeys(keys: [K], notFoundMarker: V) -> [V] { 
            // To be implemented
     }
}

在Swift中實(shí)現(xiàn)該方法與Objective-C有點(diǎn)不同伺通,因?yàn)镾wift中強(qiáng)類型的特性使返回的數(shù)組中只能包含某一種類型的元素,也就是說(shuō)我們不能在一個(gè)字符串?dāng)?shù)組中添加一個(gè)NSNull類型的元素逢享,這就使notFoundMarker的參數(shù)類型顯得非常尷尬罐监。這怎么解決呢?別著急瞒爬,在Swift中我們有更好的選擇:我們可以返回一個(gè)Optional類型的數(shù)組弓柱。從Dictionary中查出的值全部被包在Optional類型中,這樣當(dāng)使用的key沒(méi)有對(duì)應(yīng)值的時(shí)候疮鲫,我們就可以使用nil來(lái)替代NSNull類型了吆你。

extension Dictionary { 
        func valuesForKeys(keys: [Key]) -> [Value?] {
                 var result = [Value?]() 
                 result.reserveCapacity(keys.count) 
                 for key in keys {  
                        result.append(self[key]) 
                 } 
                return result   
        }
}

注意:此時(shí)可能已經(jīng)有人認(rèn)為Dictionary類型中的這個(gè)方法可能沒(méi)必要寫(xiě)的這么繁瑣弦叶,你們可能已經(jīng)想到了這種情形:

extension Dictionary {  
        func valuesForKeys(keys: [Key]) -> [Value?] { 
                  return keys.map { self[$0] } 
        }
}

這段代碼和上面那段代碼的作用和結(jié)果是完全一樣的俊犯,當(dāng)keys調(diào)用map方法時(shí),其實(shí)已經(jīng)將查出的所有值都包在了Optional類型中了伤哺。這就足以說(shuō)明了為什么Swift中類型的API都那么短小精干燕侠,因?yàn)閷?shí)現(xiàn)復(fù)雜邏輯就像上述代碼中直接調(diào)用map方法一樣簡(jiǎn)單。

現(xiàn)在我們可以試著用我們擴(kuò)展的方法做一些例子:

let dict = ["A": "Amir", "B": "Bertha", "C": "Ching"]
dict.valuesForKeys(["A", "C"])
// [Optional("Amir"), Optional("Ching")]
dict.valuesForKeys(["B", "D"])
// [Optional("Bertha"), nil]
dict.valuesForKeys([])
// []

內(nèi)嵌Optional類型

現(xiàn)在我們來(lái)看看使用last屬性返回?cái)?shù)組的最后一個(gè)元素會(huì)發(fā)生什么立莉?

dict.valuesForKeys(["A", "C"]).last
// Optional(Optional("Ching"))
dict.valuesForKeys(["B", "D"]).last
// Optional(nil)
dict.valuesForKeys([]).last
// nil

看著結(jié)果我們是不是覺(jué)得很奇怪呢绢彤?我們?cè)谏鲜龃a的第一種情況下得到了嵌套的Optional類型,而在第二種情況下缺得到了包含nil
Optional類型蜓耻,為什么得到的不是Optional("Ching")nil呢茫舶?

冷靜下來(lái),我們回憶一下last屬性的是如何申明的:

var last: T? { get }

恍然大悟刹淌,原來(lái)last屬性的類型是Optional類型饶氏,這也就是說(shuō)如果TOptional類型的話,那么T?自然就是Optional(Optional)了有勾,也就是T??疹启。所以上面的情況就很容易解釋了,因?yàn)?code>T的類型Optional(String)蔼卡,所以我們得到的結(jié)果就Optional(Optional(String))喊崖。

那么Optional(nil)這種情況如何解釋呢?為什么不是Optional(Optional(nil))呢?
我們現(xiàn)在Objective-C中執(zhí)行一下上面那三種情況看一看:

[dict valuesForKeys:@[@"A", @"C"] notFoundMarker:[NSNull null]].lastObject
// @"Ching"
[dict valuesForKeys:@[@"B", @"D"] notFoundMarker:[NSNull null]].lastObject
// NSNull
[dict valuesForKeys:@[] notFoundMarker:[NSNull null]].lastObject
// nil

我們看到荤懂,不論在Swift中還是在Objective-C中茁裙,當(dāng)?shù)谝粋€(gè)參數(shù)的數(shù)組是空數(shù)組的時(shí)候,取最后一個(gè)元素的返回結(jié)果都是nil势誊,意思就是“數(shù)組是空數(shù)組呜达,那么最后一個(gè)元素肯定不存在啦”。那么在Swift中返回Optional(nil)和在Objective-C中返回NSNull的情況表明這個(gè)所謂的最后一個(gè)元素在數(shù)組中其實(shí)是存在的粟耻,只不過(guò)它就代表沒(méi)有查近。當(dāng)這種情況發(fā)生時(shí),Objective-C只能用一個(gè)占位符對(duì)象來(lái)表示挤忙,而在Swift中就可以用一個(gè)系統(tǒng)類型來(lái)表示霜威。

提供默認(rèn)值

如果我們想當(dāng)在Dictionary中查不到對(duì)應(yīng)值的時(shí)候返回一個(gè)我們指定的默認(rèn)值要怎么做呢?其實(shí)這也很簡(jiǎn)單:

extension Dictionary { 
      func valuesForKeys(keys: [Key], notFoundMarker: Value) -> [Value] { 
          return self.valuesForKeys(keys).map { $0 ?? notFoundMarker } 
      }
}
dict.valuesForKeys(["B", "D"], notFoundMarker: "Anonymous")
// ["Bertha", "Anonymous"]

當(dāng)Objective-C只能用占位符對(duì)象來(lái)做到這一點(diǎn)的時(shí)候册烈,Swift卻可以使用系統(tǒng)類型來(lái)呈現(xiàn)戈泼,并且提供了豐富的語(yǔ)法支持多樣化的返回結(jié)果。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末赏僧,一起剝皮案震驚了整個(gè)濱河市大猛,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌淀零,老刑警劉巖挽绩,帶你破解...
    沈念sama閱讀 206,378評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異驾中,居然都是意外死亡唉堪,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén)肩民,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)唠亚,“玉大人,你說(shuō)我怎么就攤上這事持痰≡钏眩” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,702評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵工窍,是天一觀的道長(zhǎng)割卖。 經(jīng)常有香客問(wèn)我,道長(zhǎng)移剪,這世上最難降的妖魔是什么究珊? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,259評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮纵苛,結(jié)果婚禮上剿涮,老公的妹妹穿的比我還像新娘言津。我一直安慰自己,他們只是感情好取试,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,263評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布悬槽。 她就那樣靜靜地躺著,像睡著了一般瞬浓。 火紅的嫁衣襯著肌膚如雪初婆。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,036評(píng)論 1 285
  • 那天猿棉,我揣著相機(jī)與錄音磅叛,去河邊找鬼。 笑死萨赁,一個(gè)胖子當(dāng)著我的面吹牛弊琴,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播杖爽,決...
    沈念sama閱讀 38,349評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼敲董,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了慰安?” 一聲冷哼從身側(cè)響起腋寨,我...
    開(kāi)封第一講書(shū)人閱讀 36,979評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎化焕,沒(méi)想到半個(gè)月后萄窜,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,469評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡锣杂,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,938評(píng)論 2 323
  • 正文 我和宋清朗相戀三年脂倦,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了番宁。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片元莫。...
    茶點(diǎn)故事閱讀 38,059評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖蝶押,靈堂內(nèi)的尸體忽然破棺而出踱蠢,到底是詐尸還是另有隱情,我是刑警寧澤棋电,帶...
    沈念sama閱讀 33,703評(píng)論 4 323
  • 正文 年R本政府宣布茎截,位于F島的核電站,受9級(jí)特大地震影響赶盔,放射性物質(zhì)發(fā)生泄漏企锌。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,257評(píng)論 3 307
  • 文/蒙蒙 一于未、第九天 我趴在偏房一處隱蔽的房頂上張望撕攒。 院中可真熱鬧陡鹃,春花似錦、人聲如沸抖坪。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,262評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)擦俐。三九已至脊阴,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間蚯瞧,已是汗流浹背嘿期。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留埋合,地道東北人秽五。 一個(gè)月前我還...
    沈念sama閱讀 45,501評(píng)論 2 354
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像饥悴,于是被迫代替她去往敵國(guó)和親坦喘。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,792評(píng)論 2 345

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