Dartの世界へようこそ。Dart VMの心臓部からコードを見つめてきた身として、今日は皆さんが必ず一度は立ち止まる「Null安全とカプセル化のジレンマ」について語りましょう。
FlutterやDartで開発していると、「値はまだないけれど、後で必ず代入する」という状況に出くわしますよね。ここで適当に `?` を付けてNull許容型にしてしまうと、後のコードすべてで `!` や `?.` が必要になり、コードがNullの残骸で埋め尽くされてしまいます。
今回は、「外部には常に非Null(Non-nullable)として振る舞わせつつ、内部で安全に初期化を管理する」という、Dartの美しいカプセル化テクニックを伝授します。
—
1. なぜ「外部から非Null」に見せる必要があるのか?
DartのSound Null Safetyは、「実行時にNullPointerExceptionを起こさない」ことをコンパイラが保証する仕組みです。
もし公開しているAPIが `String? name` を返すと、呼び出し側は「この値はNullかもしれないから、チェックしないとな」と常に警戒しなければなりません。これは呼び出し側の負担を増やします。
理想的な設計はこれです。
- 内部: 初期化までの「Null状態」を許容する(プライベート変数)
- 外部: 初期化済みであると確約し、Nullを意識させない(パブリックGetter)
—
2. 現場で使う「LateとGetter」の鉄板テクニック
多くの初学者が「とりあえず `late` をつければいいや」と考えますが、それでは「本当に初期化されたか」をチェックできません。そこで、プライベート変数とGetterを組み合わせる手法を使います。
class UserProfile {
// 1. 内部的にはNullを許容するプライベート変数
String? _name;
// 2. 外部には非Nullとして提供するGetter
// ここで「未初期化なら例外を投げる」という仕様を明示する
String get name {
final value = _name;
if (value == null) {
throw StateError(‘UserProfile: nameが初期化される前にアクセスされました。’);
}
return value;
}
// 3. 初期化を行うセッター
set name(String value) {
_name = value;
}
}
このコードの何が「極限」なのか?
- 安全性: 外部からは `String` 型として扱えるため、Nullチェックのコードを書く必要がありません。
- 可視性: `_name` はプライベートなので、外部からは直接操作できません。
- デバッグ可能性: 万が一アクセス順序を間違えても、適当なNullを返さずに `StateError` で即座に落ちるため、バグの所在が明確になります。
—
3. よくある間違い:なぜ「late」単体では不十分なのか?
「じゃあ `late String name;` と書けば楽じゃないですか?」という声が聞こえてきそうですね。確かに `late` は強力ですが、以下の罠があります。
late String name; // 宣言
// どこかで代入するのを忘れると…
print(name); // 実行時に LateInitializationError が発生!
`late` はコンパイラを黙らせる魔法の言葉ですが、「初期化前にアクセスしたかどうか」を制御する余地がありません。 複雑なアプリで、非同期処理の後に値を入れたいようなケースでは、`late` よりも上記の「Getter + Nullチェック」の方が、状態を細かく制御できるため遥かに安全です。
—
4. さらに上を目指す:`late` との使い分け基準
ここがDartを掌握するための境界線です。以下のルールで使い分けてみてください。
- コンストラクタで初期化できるなら: 普通に final を使う。
- 構築時に値が確定せず、一度入れたら変わらないなら: `late final` を使う。
- ライフサイクルが複雑で、値の更新が発生したり、アクセス前にチェックを入れたいなら: 今回紹介した 「プライベート変数 + Getter」 を使う。
—
まとめ:Null安全は「制限」ではなく「設計の武器」
Null安全を「面倒なエラーを出すもの」と捉えるか、「コードの意図をコンパイラに伝えるためのツール」と捉えるかで、書くコードの質は劇的に変わります。
「外部には簡潔なインターフェースを、内部には厳格なガードを」。このバランスを保てるようになれば、あなたの書くDartコードは非常に堅牢で読みやすいものになります。
「ここをクリアすれば、Dartの基本はバッチリマスターできますよ」。
まずは手元のクラスで、安易な `?` を使わず、Getterでガードする設計を試してみてください。その一歩が、伝説のエンジニアへの道筋です。
また次の講義でお会いしましょう。Happy Coding!