作為一名程序員,我們是不會(huì)甘心止步于語(yǔ)法的“甜”,我們有永恒的動(dòng)力去揭開(kāi)這層語(yǔ)法的外衣一看究竟:)。我們?cè)?a href="http://www.itdecent.cn/p/8430e8480757" target="_blank">《Optional chaining的秘密(一)》中指出了,在類型的后面使用?表示Optional類型,而?.則是map 方法的語(yǔ)法糖。
我們今天要研究的是在類型的后面使用!意味著什么?
ImplicitlyUnwrappedOptional
只要我們隨便翻翻官方文檔,我們就能知道,下面這段代碼是編譯不過(guò)的
let x: String? = "Hello,world"
func printString(str: String) {
print(str)
}
printString(x) // error!!!!!!
原因就在于 x 被 String? 聲明為一個(gè)Optional<String>類型了,而方法printString()要求的參數(shù)是 String 類型,所以如果直接傳遞 x 會(huì)導(dǎo)致調(diào)用失敗,如果我們希望方法調(diào)用成功,那么我們需要這樣處理。
printString(x!)
我們需要使用 ! 強(qiáng)制對(duì) x 進(jìn)行拆封,使其還原為 String 類型。那么如果 ! 放在類型的后面意味著什么呢?
let x: String! = "Hello,world"
func printString(str: String) {
print(str)
}
printString(x) // ok!!!!!!
文檔把這種 let x: String! 稱為隱式拆封(implicitly unwrapped),在 implicitly unwrapped 的幫助下,我們可以看到printString(x)中的參數(shù)x不需要強(qiáng)制拆封了。難道let x: String!為我們定義了一個(gè)String類型?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類型,也就是說(shuō)它不是一個(gè)普通的類型,如果它是一個(gè)普通的SubDemo類型,那么它一定不允許為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 類型做類似 ?. 操作了,只是當(dāng)前類型是String,我們現(xiàn)在要將其適用于ImplicitlyUnwrappedOptional類型。
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類型的參數(shù)并返回一個(gè)ImplicitlyUnwrappedOptional類型的值。方法體內(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更深入的理解。