Swift 結構 (Structures)

結構 (Struct) 是 Swift 中建構程式碼的基石。不同於其他語言 (如 Objective-C 或 Java) 將 Class 視為一等公民,Swift 非常強調 Struct 的使用。在現代的 iOS 開發 (特別是 SwiftUI) 中,你會發現絕大多數的 View、Model 甚至 ViewModel 都是使用 Struct 定義的。

定義結構

使用 struct 關鍵字來定義一個結構。結構可以包含:

  • 屬性 (Properties):儲存數值。
  • 方法 (Methods):提供功能。
struct Resolution {
    var width = 0
    var height = 0
    
    // 定義一個方法來計算總像素
    func totalPixels() -> Int {
        return width * height
    }
}

自帶初始化器 (Memberwise Initializer)

Struct 有一個非常貼心的特性:Swift 編譯器會自動為你產生一個「成員逐一初始化器」。你不需要像 Class 那樣手動寫 init 方法。

// 自動產生的初始化器
let vga = Resolution(width: 640, height: 480)

// 如果屬性有預設值,你雖然可以省略,但 Memberwise Init 通常還是會要求填入
// 除非你自己定義了 init

如果你想要自定義初始化邏輯,也可以自己寫 init

struct Celsius {
    var temperatureInCelsius: Double
    
    init(fromFahrenheit fahrenheit: Double) {
        temperatureInCelsius = (fahrenheit - 32.0) / 1.8
    }
    
    init(fromKelvin kelvin: Double) {
        temperatureInCelsius = kelvin - 273.15
    }
}

值型別 (Value Types) 的意義

Struct 是值型別 (Value Type)。這在 Swift 中是一個非常核心的概念。

什麼是「值型別」?

簡單來說,當你把一個 Struct 賦值給另一個變數,或是傳遞給函式時,系統會複製 (Copy) 一份完整的內容。

生活類比: 想像你有一份 Excel 檔案。當你把這份檔案 Email 給同事時,同事收到的是一份副本。他在副本上做的任何修改 (例如刪除一行資料),完全不會影響你電腦裡原本的那份檔案。這就是 Value Type。

struct Resolution {
    var width = 0
    var height = 0
}

let hd = Resolution(width: 1920, height: 1080)
var cinema = hd // 這裡發生了「複製」行為,cinema 是一份獨立的副本

cinema.width = 2048 // 修改 cinema 的寬度

print("cinema width: \(cinema.width)") // 2048
print("hd width: \(hd.width)")         // 1920 (原值完全不受影響)

Mutating 方法

因為 Struct 是值型別,Swift 預設不允許在實體方法 (Instance Method) 中修改自身的屬性 (因為這等同於修改了「值」本身)。

如果你需要在方法中修改屬性,必須將該方法標記為 mutating

struct Point {
    var x = 0.0, y = 0.0
    
    // 必須加上 mutating 關鍵字,否則編譯錯誤
    mutating func moveBy(x deltaX: Double, y deltaY: Double) {
        x += deltaX
        y += deltaY
    }
}

var somePoint = Point(x: 1.0, y: 1.0)
somePoint.moveBy(x: 2.0, y: 3.0) // x 變為 3.0, y 變為 4.0
注意:如果你宣告實體為常數 (let),即使方法標記為 mutating 也無法呼叫,因為常數本來就不能被修改。

為什麼 Swift (和 SwiftUI) 偏愛 Struct?

  1. 安全性 (Safety):因為值是複製的,你不需要擔心資料在不知情的情況下被程式的其他部分修改。這在多執行緒環境下特別重要。
  2. 效能 (Performance):Struct 通常分配在 Stack (堆疊) 上,存取速度比分配在 Heap (堆積) 上的 Class 快得多。
  3. 不可變性 (Immutability):透過 let 宣告,我們可以輕鬆確保資料的不可變性,這讓程式邏輯更清晰、預測性更高。

事實上,Swift 內建的 Int, Double, String, Array, Dictionary 全都是 Struct!這證明了 Struct 的強大與高效。