給困惑的 Swift 初學者:struct or class?

Swift 是 Apple 精心培育的新世代程式語言,有許多精巧的設計蘊含其中。這些設計一方面讓 Swift 成為更優秀的語言,一方面卻也讓 Swift 自學者困惑不已。

最人盡皆知的大概就是 optional variable 了。雖然掌握 optional 的精神後會覺得 optional 是超精心的巧思,但第一次接觸 Swift 的人,大概會被程式碼中滿滿的問號與驚嘆號嚇傻。

所幸,關於這個人盡皆知的議題,AppCoda 已經寫了一篇《初學Swift:愛恨交織的 Optional》充分討論。

本文想要討論的是另一個也令人困惑的議題: struct v.s. class。

在其他有 struct 的語言中, struct 一般只能拿來組織邏輯相關的 data,使用上沒什麼疑義。但在 Swift 中,struct 除了可以整理相關的資料,還擁有 initializer、擁有 method ,除了無法被繼承以外,和 class 的使用方式幾乎完全一樣。這就衍生了另一個問題:在不需要繼承的情況下,到底該用 struct 還是 class?

更令人困惑的是, Apple 早期的 Swift 文件推薦開發者優先使用 class;一些近期的文件則推薦優先使用 struct。

Apple, are you kidding me? 所以,我們到底該用哪一個?

在討論這個議題前,我們需要知道一些底層的知識。

記憶體分成 heap 和 stack 兩塊。class 物件是 reference type,會被儲存在 heap ; struct 物件是 value type,會被存在 stack。一般而言, stack 的執行效率會比 heap 好,所以一模一樣的事情,交給 struct 做,理論上會比 class 有效率(根據國外網友實測,越新版的 Swift,struct 效能較強這件事越顯著)。

(關於 heap 與 stack 的差異及 reference type 和 value type 的不同,那是另外兩門大哉問,不在本文討論的範圍。有興趣的讀者可自行研究。)

不過「寫出好讀、好維護的程式碼」大部分的時候比「寫出高效能的程式碼」重要。 struct 執行效率較高絕對不是 Apple 在新文件中推廣 struct 的原因。

Protocol-Oriented Programming

Object-Oriented Programming (OOP) 是近年軟體開發的主流設計模式,但在 2015 WWDC,Apple 對這個稱霸數十載的設計模式提出挑戰。

Apple 認為,在 OOP 的架構中,假如 super class 定義過於狹窄,能繼承於此 super class 的 sub class 就會較少;為了讓 super class 較「通用」、能被較多 sub classes 繼承,開發者往往需要在 super class 中加入許多 properties,但這些 properties 卻未必是每個 sub class 都需要的。於是,OOP 為主的專案容易龐雜、且程式碼容易缺乏彈性。

於是,Apple 提出 Protocol Oriented Programming(POP),主張應該用 protocol 當作設計程式架構的基礎,以解決 OOP 容易龐雜、缺乏彈性的缺點。

對 POP 細節有興趣的讀者可以自行觀看 WWDC 影片。總之,class 能夠被繼承的特性是 OOP 的核心,但 class 有效率較差、資料容易被誤改(因為 reference type 的特性)的問題。假如改用 OOP 以外的設計模式(例如POP),我們就不必常常依賴 class 的繼承特性,自然就可以優先使用效率較佳、資料較「安全」(因為 value type 的特性)的 struct。

歸根究柢,Apple 在近期的文間開始推廣 struct,主要還是因為 Apple 在推廣 POP,在 POP 下,使用 struct 大部分的時候比使用 class 更明智。

小結

class 和 struct 在 Swift 中非常相似,傳統上,我們習慣使用 OOP,所以會優先(且「必須」)使用 class。

但 Apple 去年開始推廣 POP,在這個新的設計模式下,我們對 class 能夠繼承的特性不再那麼倚賴,所以在大部分的情境下,使用優點較多的 struct 就變比較合理的選擇。

不過 OOP 畢竟還是當前主流,Apple 自己也說 OOP 還是有優點和必要, POP 無法完全取代 OOP。

到底要用 class 還 struct ,還是需要根據個別情況斟酌。

可以確定的是,在 swift 中,稱霸數十載的 class 不再是需要使用物件時的唯一選擇了。

如果對以上主題有什麼問題或想法想交流,歡迎在下面留言!