作為一名程序員,我們是不會(huì)甘心止步于語(yǔ)法的“甜”七芭,我們有永恒的動(dòng)力去揭開(kāi)這層語(yǔ)法的外衣一看究竟:)素挽。我們?cè)?a href="http://www.reibang.com/p/8430e8480757" target="_blank">《Optional chaining的秘密(一)》中指出了,在類(lèi)型的后面使用?
表示Optional類(lèi)型狸驳,而?.
則是map
方法的語(yǔ)法糖预明。
我們今天要研究的是在類(lèi)型的后面使用!
意味著什么?
ImplicitlyUnwrappedOptional
只要我們隨便翻翻官方文檔,我們就能知道耙箍,下面這段代碼是編譯不過(guò)的
let x: String? = "Hello,world"
func printString(str: String) {
print(str)
}
printString(x) // error!!!!!!
原因就在于 x
被 String撰糠?
聲明為一個(gè)Optional<String>類(lèi)型了,而方法printString()要求的參數(shù)是 String
類(lèi)型辩昆,所以如果直接傳遞 x
會(huì)導(dǎo)致調(diào)用失敗阅酪,如果我們希望方法調(diào)用成功,那么我們需要這樣處理汁针。
printString(x!)
我們需要使用 !
強(qiáng)制對(duì) x
進(jìn)行拆封术辐,使其還原為 String
類(lèi)型。那么如果 !
放在類(lèi)型的后面意味著什么呢扇丛?
let x: String! = "Hello,world"
func printString(str: String) {
print(str)
}
printString(x) // ok!!!!!!
文檔把這種 let x: String!
稱(chēng)為隱式拆封(implicitly unwrapped),在 implicitly unwrapped
的幫助下术吗,我們可以看到printString(x)
中的參數(shù)x
不需要強(qiáng)制拆封了。難道let x: String!
為我們定義了一個(gè)String
類(lèi)型帆精?no,no,no,no
我們?cè)诳匆粋€(gè)長(zhǎng)一點(diǎn)的例子。
public class Demo {
public var subDemo: SubDemo! = nil
}
public class SubDemo {
public let count: Int = 1
}
let demo: Demo! = Demo()
demo.subDemo = SubDemo()
let count = demo.subDemo.count
在這個(gè)代碼片段中,我們有兩處值得注意:
-
public var subDemo: SubDemo! = nil
可以被聲明為nil -
let count = demo.subDemo.count
可以chaining式調(diào)用
第一點(diǎn)是比較容易解釋的卓练,subDemo
之所以可以被聲明為nil是因?yàn)椋?code>SubDemo!聲明了一個(gè)ImplicitlyUnwrappedOptional
類(lèi)型隘蝎,也就是說(shuō)它不是一個(gè)普通的類(lèi)型,如果它是一個(gè)普通的SubDemo
類(lèi)型襟企,那么它一定不允許為nil.
如何完成鏈?zhǔn)降恼{(diào)用
那怎么解釋第二點(diǎn)嘱么,鏈?zhǔn)秸{(diào)用呢?讓我們循序漸進(jìn),我們現(xiàn)在有這樣個(gè)方法顽悼,可以給一個(gè)string做擴(kuò)展
extension String {
static func appendingString(str: String) -> (String) -> String {
return { str + $0 }
}
}
var aStr = "Hello"
var bString = String.appendingString(aStr)("!")
var method = String.appendingString(aStr)
var cStr = method("!")
現(xiàn)在我們定義個(gè)操作符方法:+-
它可以幫助我們實(shí)現(xiàn)上面同樣的功能
infix operator +- { associativity left }
func +-<T,Z>(obj:T, f:T->Z) -> Z {
return f(obj)
}
通過(guò)這個(gè)中綴操作符的定義曼振,我們可以這樣實(shí)現(xiàn)給一個(gè)字符做擴(kuò)展的功能。
let helloString = "hello" +- {
String.appendingString($0)("!")
}
操作符 +-
接收兩個(gè)參數(shù)蔚龙,一個(gè)是字符串"hello"
,另外一個(gè)是閉包冰评。而且通過(guò)associativity
的聲明,這種操作可以還可以產(chǎn)生一個(gè)連綴式調(diào)用木羹。
let helloString = "hello" +- {
String.appendingString($0)("!")
} +- { String.appendingString($0)("!") }
說(shuō)了這么多甲雅,不知道我們又沒(méi)有注意,我們現(xiàn)在已經(jīng)可以對(duì) String 類(lèi)型做類(lèi)似 ?.
操作了坑填,只是當(dāng)前類(lèi)型是String
,我們現(xiàn)在要將其適用于ImplicitlyUnwrappedOptional
類(lèi)型抛人。
infix operator +- { associativity left }
func +-<T,Z>(obj:ImplicitlyUnwrappedOptional<T>, f:T->Z) -> ImplicitlyUnwrappedOptional<Z> {
switch obj {
case .Some(let x):
return f(x)
case .None:
fatalError()
}
}
我們重新實(shí)現(xiàn)操作符 +-
的定義,使其接收一個(gè)ImplicitlyUnwrappedOptional
類(lèi)型的參數(shù)并返回一個(gè)ImplicitlyUnwrappedOptional
類(lèi)型的值脐瑰。方法體內(nèi)容會(huì)對(duì)參數(shù)obj
進(jìn)行拆包妖枚,如果為nil
則會(huì)報(bào)錯(cuò),否則經(jīng)過(guò)轉(zhuǎn)換后返回ImplicitlyUnwrappedOptional
苍在,這不就是完整的implicitly unwrapped
的工作過(guò)程嗎绝页?好,現(xiàn)在我們把String聲明為implicitly unwrapped
var oldString: String! = "hello" // String!
let helloString = oldString +- {
String.appendingString($0)("!")
} +- { String.appendingString($0)("!") }
這就是Optinal chaining
在 implicitly unwrapped
是的工作過(guò)程忌穿。
總結(jié)
以上代碼在xcode 7.3上都測(cè)試通過(guò)抒寂。雖然代碼沒(méi)有swift的鏈?zhǔn)讲僮鞣a那樣漂亮,但這些功能確實(shí)可以通過(guò)純swift代碼來(lái)實(shí)現(xiàn)掠剑。希望這些內(nèi)容有助于大家對(duì)optional
更深入的理解屈芜。