1. 程式人生 > >Swift中?和!使用總結

Swift中?和!使用總結

Optional(可選型別)

Swift的可選(Optional)型別,用於處理值缺失的情況。可選表示“那兒有一個值,並且它等於x”或者“那兒沒有值,為nil”。它的定義通過在型別聲明後加一個 ? 操作符來完成的 :

var str = String?

Optional 其實是個 enum ,裡面有 NoneSome 兩種型別。其實所謂的 nil 就是 Optional.None ,當你宣告一個可選變數的時候沒有提供初始值,它的值預設為 nil 。 非nil 就是 Optional.Sonme ,然後會通過 Some(T) 包裝(wrap)原始值,這也是為什麼在使用 Optional

的時候要拆包(unwrap : 從 enum 中取出來原始值)的原因x。下面是 enum Optional 的定義 :

public enum Optional<Wrapped> : ExpressibleByNilLiteral {

    case none

    case some(Wrapped)

    public init(_ some: Wrapped)

    public func map<U>(_ transform: (Wrapped) throws -> U) rethrows -> U?

    public func flatMap<U>(_ transform: (Wrapped) throws -> U?) rethrows -> U?

    public
init(nilLiteral: ()) public var unsafelyUnwrapped: Wrapped { get } }

既然這樣, 那我們如何理解上述變數的宣告呢?

var str = String?
//我聲明瞭一個Optional型別的變數,它可能包含一個String值,也可能什麼都不包含,即nil

也就是說我們實際上宣告的是一個 Optional 型別,而不是 String 型別。

? 和 ! 的比較

舉例 :

import Cocoa
var str : String?
str = "Hello World"
if str != nil
{ //print(str) print(str!) } else { print("字串為nil") }

輸出結果為: Hello World

怎麼使用 Optional 值呢?在蘋果文件中也有提到說,在使用 Optional 值的時候需要在具體的操作,比如呼叫方法、屬性、下標索引等前面需要加上一個?,如果是 nil 值,也就是 Optional.None ,會跳過後面的操作不執行,如果有值,就是 Optional.Some ,可能就會拆包(unwrap),然後對拆包後的值執行後面的操作,來保證執行這個操作的安全性。

舉例如下:

let length = str?.count
//如果你確定有值得話,也可以這樣寫
//let length = str!.count

注意

  1. 如果是執行 print(str) 這句話,那麼輸出為 Optional("Hello World")
  2. 使用 ! 來獲取一個不存在的可選值會導致執行時錯誤。使用 ! 來強制解析值之前,一定要確定可選包含一個 非nil 的值。

拆包(unwrap)

上文提到 Optional 值需要拆包才能得到原來值,並判斷其值是否為空才能對其操作。下面介紹兩種拆包方法:

1.可選繫結(optional binding)

使用可選繫結(optional binding)來判斷可選型別是否包含值,如果包含就把值賦給一個臨時常量或者變數。可選繫結可以用在if和while語句中來對可選型別的值進行判斷並把值賦給一個常量或者變數。
舉例如下:

import Cocoa

var str : String? = "Hello"
let world = "World"
if let const = str{
    print(const + " " + world)
}
else {
    print("str is nil")
}

2.硬解包
即直接在可選型別後面加一個 ! 來表示它肯定有值。
舉例如下:

import Cocoa

var str : String? = "Hello"
let world = "World"
if str != nil{
    print(str! + " " + world)
}
else {
    print("str is nil")
}

錯誤示範

import Cocoa

var str:String?
let world = "Hi"
print(str! + world)

以上程式碼在編譯階段不會報錯.因為使用了硬解包, 編譯器認為可選型別是有值的, 所以編譯是通過的。當代碼執行起來時,會報錯:
Fatal error: Unexpectedly found nil while unwrapping an Optional value.

隱式拆包(自動解析)

你可以在宣告可選變數時使用感嘆號 ! 替換問號?。這樣可選變數在使用時就不需要再加一個感嘆號 ! 來獲取值,它會自動解析。
舉例如下 :

import Cocoa

var str:String!
str = "Hello World!"

if str != nil {
   print(str)
}else{
   print("str is nil")
}

等於說你每次對這種型別的值操作時,都會自動在操作前補上一個 ! 進行拆包,然後在執行後面的操作,當然如果該值是 nil ,會報錯crash掉。

總而言之,?! 坑還是很多的,需要不斷在實踐中檢驗和體會。


參考自 :
- https://www.jianshu.com/p/89a2afb82488
- http://www.runoob.com/swift/swift-optionals.html