重讀 swift 之一:Optional(可選型)

發表於2016-08-07

之前學習 swift 的時候都是比較破碎,零零散散,以至於有些地方學習的不夠透徹。所以趁最近有時間,就開始重新學習 swift ,從最基本的開始學習,希望能深入理解,見微知著!
關於 swift 我們都是到是型別安全型的,相較於 OC ,安全似乎更能體現出來。關於這一方面, swift的可選型(optional)就不得不說了,可選型可以說是 swift 最為突出的特性之一。可能有的同學在看 swift 的過程中會遇到可選型(比如 String? ),有時也會見到 String! 這樣的,搞不明白其中的意思,所以今天就來一步步理解可選型。

一、什麼是 Optional


optional 是 swift 新加入的型別,所以學過 OC 的童鞋就知道在 OC 中是沒有這個概念的。可選型的意思簡單理解是:有值得時候就有值,無值的時候就是 nil 。swift 中的 nil 和其他語言中的 nil 還有些不一樣,nil 自己本身就是一種型別,沒有就是 nil ,是和其他型別嚴格區分開的。
可選型的定義很簡單:型別 + ? 。比如 String?Int?Float? 等,這裡需要注意的是 String?String 是完全不同的兩個型別,前者是 String 型別的額可選型,後者是 String 型別,注意區分。舉個例子,在 OC 中我們可以這樣寫

上面的這種寫法在 OC 中是沒有問題的,相比於上面,在 swift 中

如果我們像上面程式碼中這樣寫就會報錯,如下

11571495-1af13cff33c0abd2
error

說的是 nil 是不可以分配給 String 型別的,這也說明在 swift 中 nil 是和其他型別嚴格區分的。改為可選型即可,

可選型,顧名思義就是可以選擇,比如 String? 的意思就是可以在 Stringnil 之間選擇,可以是 String 也可以是 nil 。如果一個變數定義成 String,那麼這個變數就會是 String 型別,而不可能是nil
還有一點需要注意的是宣告可選型必須是顯示的宣告也就是必須是

這樣,而不能是

這樣,因為 swift 在做型別判斷的時候無法判斷 name 到底是 String 型別的可選型還是其他型別的可選型,因此會導致編譯錯誤。

二、Optional的解包


可選型是不能夠被直接使用的(因為 swift 是型別安全的,可選型的值又可能會是 nil,如果不做處理可能導致程式 crash),如果我們想使用可選型的值,那麼在這之前我們需要做的一項工作就是:解包(unwarp)!

  • 1、強制解包
    所謂的強制解包意思就是我知道這個型別是可選型,但是在我的程式執行到這裡的時候我可以保證它是有值得,所以我要在這裡使用它。具體表現形式就是在可選型後面加個 !,如下

    但是這樣的解包是不安全,因為你不知道什麼時候你的這個可選型就會變成 nil,如果我們程式碼非常多的話,一不小心為 nil了,可能會導致程式崩潰。這個時候我們會想到一種方法:判空!如下,

    這樣寫似乎是沒有什麼問題了,但是需要注意的是,你在判斷非 nil 的作用域內使用 name 的時候還必須把 ! 帶上,這樣程式碼比較多的時候還是比較麻煩。於是我們可以使用下面這種方式,
  • 2、使用 if let 解包
    使用 if let 解包如下,

    這種解包方式可以保證 name 是解包過的,不會再是 nil 這種情況,其實邏輯是和上面做非空判斷一樣的。當然你把 let 換成 var 也是可以的,效果是一樣的,只不過我們一般要用的是解包後的值,而不會去改變它,所以平常使用中一般都是用 if let
    同時 if let 可以同時一次性解包多個可選型,用 , 隔開,使語句簡潔,如下

    最後,既然這裡使用的是 if ,那麼同樣我們可以如下這樣用,來進行進一步的判斷篩選

    如上也是可以的。

三、可選鏈式呼叫(Optional Chaining)


可選鏈式呼叫(Optional Chaining)是一種可以在當前值可能為 nil 的可選值上請求和呼叫屬性、方法及下標的方法。如果可選值有值,那麼呼叫就會成功,如果可選值是 nil ,那麼呼叫將返回 nil。多個呼叫可以連線在一起形成一個呼叫鏈,如果其中任何一個節點為 nil ,整個呼叫鏈都會失敗,即返回 nil 。
下面我們就來舉個例子具體說明可選鏈,如下

我們來解包 name ,如果有值就列印出 name 的大寫,如果沒有就輸出 name is nil ,其實上面這段程式碼完全等同於

上面這句程式碼的意思就是如果可選型變數 name 有值,那麼就對 name 進行解包,並得到 name 的uppercaseString 值,如果沒有,那麼這句程式碼就會返回一個 nil 。這樣就符合 swift 的型別安全,完全是沒有問題的。但是如果你寫成

也是可以的,不過不安全,因為如果 name 沒有值,你進行強制解包,就會報錯。
所以我們以後可能會用到類似於 person?.name?.uppercaseString 這樣的一層層解包的,這種就是可選鏈。

四、Nil Coalescing Operator(空合運算子)


如上,如果我們想把解包後的值存起來的話,可以這樣

上面程式碼的意思就是如果 name 為 nil ,newName 就是 “no name”,否則 newName 就是 name!(name的解包)。其實 swift 為我們提供了更簡潔的語法,如下

上面程式碼的意思就是 name 如果有值 newName2 的值就是 name! ,否則就是 no name 。這裡需要注意的是 ??是空合運算子,這樣寫的可閱讀性強,比較簡潔。
當然關於 ?? 遠不止這些,有興趣的同學可以看 聊聊swift語言中的“??” 這篇文章。

五、隱式可選型


上面我們都知道了,建立一個顯示可選型是: 型別 + ?。這裡建立顯示可選型的就是: 型別 + !

這裡可能有的童鞋會疑惑,已經有了顯示的可選型,為什麼還需要有隱式的可選型。這裡其實隱式的可選型也是有一定作用的。比如你有一個變數,宣告為隱式的可選型(!),它的作用就是,當你這個類沒有被初始化的時候他是沒有值的,但是當你這個類初始化以後,你可以確保他是有值的,所以這裡宣告為隱式的可選型,而不是顯示的。同樣需要注意的是隱式的可選型也是可選型,如果你需要用它的值,你也是要進行判斷的。如果不進行判斷而直接使用,可能會造成不可預料的後果!
差不多可選型就到這裡了,如果還有什麼遺漏,歡迎大家指正!

參考連結:可選鏈式呼叫(Optional Chaining)

相關文章