Swiftを学習する中で、遅延保存プロパティ(lazy stored property)はvarでのみ宣言できる一方で、タイプ保存プロパティ(type stored property)はletとvarの両方で宣言可能であることに気付きました。この違いについて、具体的なコード例を交えて考察してみます。
1. コード例
以下のAnimation
クラスを見てみましょう。
class Animation {
static let genere = "animation" // タイプ保存プロパティ
let name: String
var rate: Double
lazy var series: Int = 0 // 遅延保存プロパティ
init(name: String, rate: Double) {
self.name = name
self.rate = rate
}
}
このクラスには以下のプロパティが含まれています。
-
genere
: タイプ保存プロパティ(static let) -
series
: 遅延保存プロパティ(lazy var)
次の3つの手順でプロパティの挙動を確認してみましょう。
-
ani
というインスタンスを生成 → 確認 -
series
(遅延保存プロパティ)にアクセス → 確認 -
genere
(タイプ保存プロパティ)にアクセス → 確認
[1]インスタンスの生成
let ani = Animation(name: "ani", rate: 3.0) // インスタンス生成
ani
インスタンスを生成すると、遅延保存プロパティseries
はまだ初期化されていません。デバッグ情報を確認すると、$__lazy_storage_$_series
という内部変数が nil
になっていることが分かります。
[2] 遅延保存プロパティにアクセス
ani.series // 遅延保存プロパティにアクセス
ani
このタイミングで初めて series
に値が設定されます。アクセスする前までは nil
だったのが、値 0
に変更されていることが確認できます。
[3] タイプ保存プロパティにアクセス
Animation.genere // タイプ保存プロパティにアクセス
ani
タイプ保存プロパティgenere
にアクセスしても、インスタンスani
の状態には何の変化もありません。これは、タイプ保存プロパティがインスタンスに属するものではなく、クラス(型)そのものに属するプロパティだからです。
2. 結論
遅延保存プロパティ(lazy stored property)
- アクセスするまで初期化されない
- 初期化される前は、
nil
の状態(内部的にはOptional型として扱われる) -
let
はインスタンス生成時に値を必ずセットする必要があるため、lazy
とは相性が悪い - そのため、
lazy
はvar
としか併用できない
つまり、遅延保存プロパティは「値の設定の遅延」が目的であり、var
のみ許容されるということになります。
タイプ保存プロパティ(type stored property)
- 最初にアクセスされるまでメモリのデータ領域にロードされない(=lazyな動作)
-
let
とvar
の両方が可能(値の変更可否に依存する) - メモリのデータ領域を効率よく使用するために、アクセスされたときに初めてロードされる
つまり、タイプ保存プロパティは「メモリ効率の向上」が目的であり、lazyな動作をするが、値の変更可否(let/var)とは独立しているということになります。
3. まとめ
プロパティの種類 | let使用 | var使用 | 初期化のタイミング |
---|---|---|---|
インスタンス保存プロパティ | ○ | ○ | インスタンス生成時 |
遅延保存プロパティ(lazy) | ❌ | ○ | 最初にアクセスされたとき |
タイプ保存プロパティ(static) | ○ | ○ | 最初にアクセスされたとき |
-
遅延保存プロパティは、インスタンスのプロパティとして初期化の遅延が目的 →
let
と相性が悪いためvar
のみ -
タイプ保存プロパティは、メモリの効率化が目的 →
let
/var
どちらも可能
このように、遅延保存プロパティのlazyと、タイプ保存プロパティのlazyな挙動は、それぞれ目的が異なるため、let
の使用可否にも違いが生じるということが分かりました。
⚠️ 注意:
この文書の内容には誤りが含まれている可能性があります。
もし間違いや改善点がありましたら、ご指摘いただけると幸いです。