使用 Swift 開發時,總會遇到至少一次讓你停下來思考的時刻。
「這個要做成 class,還是 struct?」
我剛開始學 Swift 時,也只是憑感覺選這兩者。直到遇到奇怪的錯誤,才真正研究它們的差異。
先說結論。
如果沒有特殊理由,請優先選擇結構(struct)。
只有在確實需要「共享的一份狀態」時,才使用類別。
Apple 的官方指南也是同樣的立場。今天就來逐一說明原因。
先看重點摘要(3 點)
先為忙碌的讀者整理重點。
- 結構是值型別。複製後會成為完全不同的值。
- 類別是參考型別。即使複製,仍會共同指向同一個實例。
- 如果搞不清楚,先用 struct,只有需要繼承或共享狀態時才用 class。
記住這三句,就完成一半了。
值型別與參考型別有什麼不同?
只用文字說明確實有點難懂。直接看程式碼最快。
先看結構。複製的瞬間,兩者就互不相干了。
struct Point { var x = 0 }
var a = Point()
var b = a // 值已複製
b.x = 10
print(a.x, b.x)
// 輸出: 0 10
即使修改了b,a仍然不變,因為兩者各自擁有自己的值。
接著看類別。程式碼看起來相同,但結果不同。
class Box { var x = 0 }
let a = Box()
let b = a // 參考已複製(相同物件)
b.x = 10
print(a.x, b.x)
// 輸出: 10 10
只修改了b,結果a也變成 10 了。
因為兩者指向同一個實例。那個困擾我的錯誤就是這個。
那麼什麼時候該用哪一個?(選擇標準)
在實務上做判斷時,我會在腦中想起這張表。
| 情況 | 判斷 |
|---|---|
| 單純用來容納資料的模型 | 結構 |
| 希望複製後彼此保持獨立 | 結構 |
| 必須使用繼承 | 類別 |
| 在多個地方共享同一個實例 | 類別 |
| 需要與 Objective-C 互通 | 類別 |
再詳細整理一下,就是這樣。
- 如果要表示座標、色彩、大小等值本身,使用結構很自然。
- 像畫面控制器或網路管理器一樣,需要讓多個地方共同查看同一份狀態時,類別才是合適的選擇。
- Apple 的 SwiftUI 也基於相同理由,將 View 定義為 struct,因為它輕量且容易預測。
順帶一提,Swift 標準函式庫中的Array、String、Dictionary全都是結構。這表示值型別就是基本選擇。
優先推薦結構的理由
值型別容易預測。
不用擔心自己傳出的值在其他地方被偷偷修改。即使傳給函式,原始值也很安全。
在多執行緒環境中也更放心。因為沒有共享狀態,資料競爭會減少。
相反地,類別雖然強大,卻需要小心使用。如果同一個實例被各處持有,就很難追蹤值究竟在哪裡改變。
因此養成「預設使用 struct,需要時才用 class」的習慣,能大幅減少錯誤。
何時使用,何時避免?
最後將判斷標準簡短整理如下。
- 使用結構:以資料為中心的模型、需要獨立複製,以及重視執行緒安全時
- 使用類別:需要繼承、必須共享單一實例,或識別(identity)具有意義時
- 避免:習慣性地為簡單模型使用 class,或需要共享時硬要用 struct 迂迴處理
面試時會這樣問
Q. 結構與類別最大的差異是什麼?
結構是值型別,類別是參考型別。結構複製後會成為完全獨立的值,但類別即使複製仍指向同一個實例。此外,只有類別可以繼承並定義 deinit。
Q. Swift 為什麼建議使用結構?
因為值型別沒有共享狀態,副作用較少且容易預測。原始值不會在意外情況下被修改,在多執行緒環境中也安全,有助於減少錯誤。
一開始我也以為這只是語法差異,但越深入研究,越發現這其實是設計問題。
熟悉今天的判斷標準,從下一個專案開始就不會那麼猶豫。先問自己:是值,還是共享?

