値型と参照型
Swift の設計で最も影響が大きい区別。
| 値型 (value type) | 参照型 (reference type) | |
|---|---|---|
| 該当 | struct、enum、タプル |
class、actor、クロージャ |
| 代入 | コピーされる | 同じ実体を指す |
| 同一性 | 無い(== のみ) |
=== で比較できる |
| 既定の格納 | スタック(インライン) | ヒープ |
| 寿命管理 | スコープで決まる | ARC |
swift
struct P { var x = 0 }
var a = P(); var b = a
b.x = 10
// a.x は 0 のまま
class C { var x = 0 }
let c = C(); let d = c
d.x = 10
// c.x も 10なぜ値型を既定にするのか#
共有された可変状態が、バグの主要な源だから。
参照型では
- どこから変更されるか分からない
- [競合状態](/コンピュータ/並行・並列処理/Race Condition)が起きる
- 変更が意図しない場所に波及する
値型はコピーされるので、 渡した先で変更されても自分は影響を受けない。 局所的に考えられる。
コピーのコスト#
大きな構造体を毎回コピーすると遅そうだが、 標準ライブラリのコレクション(Array、Dictionary、String)は コピーオンライトを実装している。
代入時 … 参照を共有するだけ(O(1))
書き込み時 … このとき初めて実体を複製する参照カウントが 1 なら複製すら不要。 fork の CoW と同じ発想。
使い分け#
| 値型を選ぶ | 参照型を選ぶ |
|---|---|
| データを表す | 同一性が意味を持つ |
| 不変・独立 | 状態を共有したい |
| 比較が値の比較 | 継承が必要 |
| 並行処理で渡す | Objective-C 連携 |
迷ったら struct というのが Swift の指針。
参考文献#
- Apple. The Swift Programming Language. https://docs.swift.org/swift-book/
- Apple. Choosing Between Structures and Classes. https://developer.apple.com/documentation/swift/choosing-between-structures-and-classes