Optional chaining的秘密(二)

作為一名程序員,我們是不會(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!!!!!!

原因就在于 xString? 聲明為一個(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 chainingimplicitly 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更深入的理解。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 基礎(chǔ)部分(The Basics) 當(dāng)推斷浮點(diǎn)數(shù)的類型時(shí),Swift 總是會(huì)選擇Double而不是Float。 結(jié)合...
    gamper閱讀 1,487評(píng)論 0 7
  • 對(duì)各種值為"空"的情況處理不當(dāng),幾乎是所有Bug的來(lái)源。 在我們的例子里,盡管tmp的值是nil,但調(diào)用tmp的r...
    AKyS佐毅閱讀 10,675評(píng)論 1 13
  • Swift 是一門(mén)開(kāi)發(fā) iOS, macOS, watchOS 和 tvOS 應(yīng)用的新語(yǔ)言。然而,如果你有 C 或...
    XLsn0w閱讀 983評(píng)論 2 1
  • 聊聊費(fèi)蘭克的寫(xiě)作訓(xùn)練營(yíng) 近來(lái)喜歡上了寫(xiě)作,而且想提高一下寫(xiě)作水平,又偶然知道了一個(gè)叫做費(fèi)蘭克的家伙花了十多萬(wàn)去學(xué)習(xí)...
    簡(jiǎn)單國(guó)平閱讀 473評(píng)論 2 49
  • 江梅從一片混沌中醒來(lái)的時(shí)候,厚重的遮光窗簾嚴(yán)實(shí)地?fù)踝×舜巴獾木跋螅虼怂矡o(wú)法辨認(rèn)此刻到底是白晝還是黑夜。 黑暗中...
    _云本_閱讀 268評(píng)論 0 1

友情鏈接更多精彩內(nèi)容