這篇文章將帶我們探索在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ō)如果T
是Optional
類型的話,那么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é)果。