Struct vs Class in Swift

Structures

structenum 是 value type instance, value type 是指當被 assign 到 constant 或 variable,或當作參數傳遞到 function 時,他的值是被 copied 過去的,在 swift 裡面 intergers, floating-point numbers, booleans, strings, arrays and dictionaries 皆為 value type

struct SWeather {
    var location: String
    var minTemp: Double
    var maxTemp: Double
}

let s = SWeather(location: "Taipei", minTemp: 12, maxTemp: 15)

接著定義一個 ss 來 assign to s

var ss = s
ss.minTemp = 10 # 設 minTemp 為 10

output:

(lldb) po s
▿ SWeather
  - location : "Taipei"
  - minTemp : 12.0 # s 的 minTemp 不會改變,因為做 assignment 時是複製一份相同的數值到 ss
  - maxTemp : 15.0

(lldb) po ss
▿ SWeather
  - location : "Taipei"
  - minTemp : 10.0 # ss 的 minTemp 已變為 10
  - maxTemp : 15.0

Classes

class 是 reference type instance, 不同於 structures,當被 assign 到 constant 或 variable,或當作參數傳遞到 function 時,會儲存一個參考位址 reference 到同一個實例

class CWeather {
    var location: String?
    var minTemp: Double = 0
    var maxTemp: Double = 0
}

let c = CWeather()
c.location = "Taipei"
c.minTemp = 12
c.maxTemp = 15

定義一個 d 並指到 c

let d = c // 指向 c
d.minTemp = 13

output:

(lldb) po c
<CWeather: 0x600001367240> # class instance 被配置到參照位址中

(lldb) po c.minTemp
13.0 # c instance 的 minTemp 也被改為 13

(lldb) po d.minTemp
13.0

相同的地方

  • 可定義 property 並保存值
  • 可定義 methods
  • 可自定義 subscripts 捷徑來存取 collection, list or sequence 的 member
  • 可自定義 initializers
  • 可使用 extension 來延伸功能性
  • 可遵從 Protocols

不同的地方

Classes 還可以做到

  • 繼承
  • 可在 runtime 作類型轉換(Type casting)
  • Deinitializers 可以釋放記憶體空間
  • Reference count

Classes 雖然提供更多的功能與彈性但相對的也提升了程式的複雜度,若在一般使用情境下,建議使用 structures 跟 enumerations 來定義,可以減少擔心 memory leaks 或多緒執行下可能造成的 data racing (access/modify),而在適當的時機或需要時才使用 classes 來定義。

使用情境

使用 struct 的情境:

  • 預設的建模方式,適用在大部分情況
  • 透過 Protocols 為繼承和共享行為建模 (Protocols Oriented Programming)
  • 不需要辨識不同 identity 時

使用 class 的情境:

  • 需與 Objective-C 做互通
  • 需要辨識不同的身份時,假設兩個 instances 有相同的 value 但可使用 === 來分辨不同的 identity
  • 不需要 Copying or comparing instances (e.g., Window)
  • 實例的 lifetime 與外部影響有關 (e.g., TemporaryFile)
  • 實例只是"接收器" 指向外部狀態的 write-only 管道 (e.g. CGContext)

References

comments powered by Disqus