swift語言新特性:可選值

openglnewbee發表於2014-06-14

var  a?  此處的a就是個可選值,意思是該值可能是缺失的.


可選

使用可選(optionals)來處理值可能缺失的情況。可選表示:

 

-有值,等於 x

 

或者

 

沒有值

 

注意:C 和 Objective-C 中並沒有可選這個概念。最接近的是 Objective-C 中的一個特性,一個方法要不返回一個物件要不返回nil,nil表示“缺少一個合法的物件”。然而,這隻對物件起作用——對於結構體,基本的 C 型別或者列舉型別不起作用。對於這些型別,Objective-C 方法一般會返回一個特殊值(比如NSNotFound)來暗示值缺失。這種方法假設方法的呼叫者知道並記得對特殊值進行判斷。然而,Swift 的可選可以讓你暗示任意型別的值缺失,並不需要一個特殊值。

 

來看一個例子。Swift 的String型別有一個叫做toInt的方法,作用是將一個String值轉換成一個Int值。然而,並不是所有的字串都可以轉換成一個整數。字串"123"可以被轉換成數字123,但是字串"hello, world"不行。

 

下面的例子使用toInt方法來嘗試將一個String轉換成Int:

  1. let possibleNumber = "123" 
  2. let convertedNumber = possibleNumber.toInt() 
  3. // convertedNumber 被推測為型別 "Int?", 或者型別 "optional Int" 

因為toInt方法可能會失敗,所以它返回一個可選的(optional)Int,而不是一個Int。一個可選的Int被寫作Int?而不是Int。問號暗示包含的值是可選,也就是說可能包含Int值也可能不包含值。(不能包含其他任何值比如Bool值或者String值。只能是Int或者什麼都沒有。)

 

if 語句以及強制解析

你可以使用if語句來判斷一個可選是否包含值。如果可選有值,結果是true;如果沒有值,結果是false。

 

當你確定可選包確實含值之後,你可以在可選的名字後面加一個感嘆號(!)來獲取值。這個驚歎號表示“我知道這個可選有值,請使用它。”這被稱為可選值的強制解析(forced unwrapping):

  1. if convertedNumber { 
  2.     println("\(possibleNumber) has an integer value of \(convertedNumber!)"
  3. else { 
  4.     println("\(possibleNumber) could not be converted to an integer"
  5. // 輸出 "123 has an integer value of 123" 

更多關於if語句的內容,請參考控制流。

 

注意:使用!來獲取一個不存在的可選值會導致執行時錯誤。使用!來強制解析值之前,一定要確定可選包含一個非nil的值。

 

可選繫結

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

 

像下面這樣在if語句中寫一個可選繫結:

  1. if let constantName = someOptional { 
  2.     statements 

你可以像上面這樣使用可選繫結來重寫possibleNumber這個例子:

  1. if let actualNumber = possibleNumber.toInt() { 
  2.     println("\(possibleNumber) has an integer value of \(actualNumber)"
  3. else { 
  4.     println("\(possibleNumber) could not be converted to an integer"
  5. // 輸出 "123 has an integer value of 123" 

這段程式碼可以被理解為:

 

“如果possibleNumber.toInt返回的可選Int包含一個值,建立一個叫做actualNumber的新常量並將可選包含的值賦給它。”

 

如果轉換成功,actualNumber常量可以在if語句的第一個分支中使用。它已經被可選包含的值初始化過,所以不需要再使用!字尾來獲取它的值。在這個例子中,actualNumber只被用來輸出轉換結果。

 

你可以在可選繫結中使用常量和變數。如果你想在if語句的第一個分支中操作actualNumber的值,你可以改成if var actualNumber,這樣可選包含的值就會被賦給一個變數而非常量。

 

nil

你可以給可選變數賦值為nil來表示它沒有值:

  1. var serverResponseCode: Int? = 404 
  2. // serverResponseCode 包含一個可選的 Int 值 404 
  3. serverResponseCode = nil 
  4. // serverResponseCode 現在不包含值 

注意:nil不能用於非可選的常量和變數。如果你的程式碼中有常量或者變數需要處理值缺失的情況,請把它們宣告成對應的可選型別。

 

如果你宣告一個可選常量或者變數但是沒有賦值,它們會自動被設定為nil:

  1. var surveyAnswer: String? 
  2. // surveyAnswer 被自動設定為 nil 

注意:Swift 的nil和 Objective-C 中的nil並不一樣。在 Objective-C 中,nil是一個指向不存在物件的指標。在 Swift 中,nil不是指標——它是一個確定的值,用來表示值缺失。任何型別的可選都可以被設定為nil,不只是物件型別。

 

隱式解析可選

如上所述,可選暗示了常量或者變數可以“沒有值”。可選可以通過if語句來判斷是否有值,如果有值的話可以通過可選繫結來解析值。

 

有時候在程式架構中,第一次被賦值之後,可以確定一個可選總會有值。在這種情況下,每次都要判斷和解析可選值是非常低效的,因為可以確定它總會有值。

 

這種型別的可選被定義為隱式解析可選(implicitly unwrapped optionals)。把想要用作可選的型別的後面的問號(String?)改成感嘆號(String!)來宣告一個隱式解析可選。

 

當可選被第一次賦值之後就可以確定之後一直有值的時候,隱式解析可選非常有用。隱式解析可選主要被用在 Swift 中類的構造過程中,請參考類例項之間的迴圈強引用。

 

一個隱式解析可選其實就是一個普通的可選,但是可以被當做非可選來使用,並不需要每次都使用解析來獲取可選值。下面的例子展示了可選String和隱式解析可選String之間的區別:

  1. let possibleString: String? = "An optional string." 
  2. println(possibleString!) // 需要驚歎號來獲取值 
  3. // 輸出 "An optional string." 
  4.  
  5. let assumedString: String! = "An implicitly unwrapped optional string." 
  6. println(assumedString)  // 不需要感嘆號 
  7. // 輸出 "An implicitly unwrapped optional string." 

你可以把隱式解析可選當做一個可以自動解析的可選。你要做的只是宣告的時候把感嘆號放到型別的結尾,而不是每次取值的可選名字的結尾。

 

注意:如果你在隱式解析可選沒有值的時候嘗試取值,會觸發執行時錯誤。和你在沒有值的普通可選後面加一個驚歎號一樣。

 

你仍然可以把隱式解析可選當做普通可選來判斷它是否包含值:

  1. if assumedString { 
  2.     println(assumedString) 
  3. // 輸出 "An implicitly unwrapped optional string." 

你也可以在可選繫結中使用隱式解析可選來檢查並解析它的值:

  1. if let definiteString = assumedString { 
  2.     println(definiteString) 
  3. // 輸出 "An implicitly unwrapped optional string." 

注意:如果一個變數之後可能變成nil的話請不要使用隱式解析可選。如果你需要在變數的生命週期中判斷是否是nil的話,請使用普通可選型別。

 

相關文章