Swift 可選型別 (Optionals)

可選型別 (Optionals) 是 Swift 中用來處理「值可能不存在」情況的核心機制。這也是 Swift 與 C 或 Objective-C 最大的不同點之一。

什麼是 Optional?

在 Swift 中,一個普通的變數 (如 IntString) 永遠不能nil (空值)。這保證了當你存取一個普通變數時,它一定有值,這消除了巨大的潛在錯誤來源。

但有時候我們確實需要表示「沒有值」的概念。這時,我們就使用 Optional

要在型別後面加上問號 ? 來定義一個 Optional:

var serverResponseCode: Int? = 404
// serverResponseCode 包含一個 Int 值 404

serverResponseCode = nil
// 現在 serverResponseCode 不包含任何值
只有 Optional 型別的變數才能被設為 nil。如果你宣告 var x: Int = 404,再嘗試 x = nil,編譯器會報錯。

什麼是 nil?

即便你曾寫過 Objective-C,Swift 的 nil 概念也與你所認知的不同。

在 Swift 中,nil 不是一個指標 —— 它代表的是特定型別的值不存在 (Absence of a value)。任何類型的 Optionals 都可以被設為 nil,不僅僅是物件型別 (Object types),還包括像 IntFloatBool 這樣的結構 (Structures) 與基礎型別。

解包 (Unwrapping)

Optional 就像是一個包裝精美的盒子。盒子裡面可能裝著一個值 (比如整數 404),也可能是空的 (nil)。

當你想使用盒子裡的值時,你必須打開這個盒子檢查。這個動作稱為解包 (Unwrapping)

1. 強制解包 (Force Unwrapping)

如果你百分之百確定盒子裡一定有值,你可以使用驚嘆號 ! 來強制打開它:

var myOptional: String? = "Hello"

if myOptional != nil {
    print("盒子裡有東西: \(myOptional!)")
}
如果你對一個值為 nil 的 Optional 使用 !,程式會立刻當機 (Crash)。因此,除非你非常有把握,否則應盡量避免使用強制解包。

2. 可選綁定 (Optional Binding) - 推薦用法

這是最常用也最安全的方式。使用 if let (或 guard let) 來檢查盒子裡有沒有值。如果有,就把值拿出來放進一個新的暫時常數中。

var possibleNumber: String? = "123"

if let actualNumber = possibleNumber {
    // 如果 possibleNumber 有值,這裡會執行
    // actualNumber 是已經解包過的 String,可以安全使用
    print("字串包含值:\(actualNumber)")
} else {
    // 如果 possibleNumber 是 nil,這裡會執行
    print("字串是 nil")
}

3. 隱式解包 (Implicitly Unwrapped Optionals)

有時候,某些 Optional 在第一次被賦值之後,我們就能確定它之後永遠都會有值。對於這種特殊的 Optional,我們可以在定義時用驚嘆號 ! 代替問號 ?

// 假設這是在 App 啟動時一定會被初始化的變數
var assumedString: String! = "An implicitly unwrapped optional string."

使用這種變數時,不需要手動解包,編譯器會自動幫你加上 !。但同樣的,如果它變成 nil 而你又去存取它,程式一樣會當機。這通常用於類別初始化 (Class Initialization) 的特定場景。

空值合併運算子 (Nil-Coalescing Operator)

使用 ?? 可以提供一個「預設值」。如果 Optional 有值就使用它,如果是 nil 就使用預設值。

let defaultColorName = "Red"
var userDefinedColorName: String? = nil

var colorNameToUse = userDefinedColorName ?? defaultColorName
// userDefinedColorName 是 nil,所以 colorNameToUse 會是 "Red"

這在處理使用者設定或預設參數時非常簡潔好用。