【入門編】Null安全下での「Getter/Setter」の設計:初期化状態をどう管理するか – Dart コア文法・オブジェクト指向・Null安全解析バイブル

こんにちは。Dartの深淵へようこそ。
Dart VMの挙動からFlutterのレンダリングパイプラインまでを設計する立場から、今日は「Null安全と初期化」という、Dart開発者が避けては通れない、かつ最も本質的なテーマについて語りましょう。

多くの開発者が「`?` をつければエラーが消える」という誤った対処療法に陥りがちです。しかし、真のDart使いは、Null安全を「制約」ではなく「コードの安全性を保証する強力な武器」として扱います。

今回は、初期化が遅延するプロパティをどう制御し、堅牢なカプセル化を行うか。その極意を伝授します。

—

1. なぜ「初期化の遅延」がNull安全の敵なのか

DartのSound Null Safetyにおいて、変数は「宣言時に値を持つ」か「nullable(`?`付き)である」必要があります。しかし、現実の開発では「インスタンス生成時には値が確定しないが、使うときには必ず存在する」という状況が頻発しますよね。

ここで「とりあえず `null` を入れておこう」とすると、後続のすべてのコードで `!`(強制アンラップ)が必要になり、コードが `!` だらけのスパゲッティ状態になります。これは設計の敗北です。

陥りやすいアンチパターン

class UserProfile {
String? _name; // nullを許容すると…

void setName(String name) => _name = name;

// 使うたびに「nullではない」ことを保証するコードが散らかる
String get name => _name!;
}

これでは、`_name` が本当に初期化されているか、実行時にしか分かりません。Sound Null Safetyの理念は「実行時エラーをコンパイル時に潰すこと」です。これを解決するスマートなアプローチを見ていきましょう。

—

2. 賢者の選択:`late` キーワードの真実

Dartには、初期化をあえて遅らせる `late` という強力な修飾子があります。

class UserProfile {
// 「後で必ず代入するから、コンパイラよ、今は文句を言うな」という宣言
late String _name;

void setName(String name) => _name = name;

// ここでは ! は不要。ただし、未代入でアクセスするとLateInitializationErrorが発生する
String get name => _name;
}

`late` を使う際の「魂の注意点」

`late` は魔法ではありません。「初期化前にアクセスしたら即座にランタイムエラー」という爆弾を抱えることになります。

  • いつ使うべきか?: コンストラクタの引数では受け取れないが、ライフサイクル上(例えば `initState` や `DIコンテナ` の解決後)に必ず値が入ることが保証されている場合。
  • 避けるべき場所: 値が空になる可能性があるデータには絶対に使わないでください。それは `?` の領域です。

—

3. カプセル化の究極形:Getterによる「計算済みプロパティ」

もし、プロパティが「他の値から算出される」ものなら、変数として保持する必要すらありません。DartのGetterは非常に強力で、評価のたびに処理を走らせることができます。

class User {
final String firstName;
final String lastName;

User(this.firstName, this.lastName);

// 変数を持たず、計算結果を返す。これが最もNull安全で安全な設計です。
String get fullName => ‘$firstName $lastName’;
}

「変数に保存する」ということは「状態の不整合」を生むリスクを抱えることです。可能であれば「計算(Getter)」で解決し、状態を最小化する。これがDartにおける美しいオブジェクト指向設計です。

—

4. 現場で使える「Null安全」設計パターン:`late final`

もし、値が一度だけ確定し、その後は不変(Immutable)であるなら、`late final` を検討してください。

class AppConfig {
late final String apiKey;

void initialize(String key) {
// 一度だけ代入可能
apiKey = key;
}
}

`late final` は、初期化のタイミングを柔軟にしながらも、一度決まったら二度と書き換えられないという「イミュータブルな安全性」を担保します。これは設定値の読み込みなどで非常に重宝します。

—

まとめ:ここをクリアすればDartはあなたの味方になる

Null安全をマスターするためのステップをまとめましょう。

1. デフォルトは非Null: 変数は原則 `null` を許容しない。
2. `?` は「本当に空になる」ときだけ: 単なる初期化待ちで `?` を使わない。
3. 初期化待ちには `late`: ただし、アクセス順序の設計には細心の注意を払う。
4. 計算できるならGetterへ: 状態を保持せず、ロジックで解決する。

Null安全は、最初は厳しく感じるかもしれません。しかし、それはDartという言語が「あなたの書くコードを、実行時のバグから守ろうとしている」という愛の証なのです。

この感覚を掴めれば、あなたはもうDartの基本を完全に掌握したと言っても過言ではありません。次は、より高度なMixinやIsolateのメモリ管理の世界でお会いしましょう。

Dartでの開発、楽しんでくださいね!

タイトルとURLをコピーしました