こんにちは!FlutterやDartを使った開発を楽しんでいますか?
世界中のコードベースを見てきたチーフアーキテクトの視点から言わせてもらうと、Dart 3で導入されたパターンマッチングとswitch式は、言語の歴史における最大のパラダイムシフトの一つです。
特に、エラーハンドリングの常識を根底から変える「Result型(成功・失敗の表現)」との組み合わせは、あなたの書くコードを劇的に美しく、そして堅牢にしてくれます。
今回は、初学者の方や他言語(TypeScriptやKotlin、Rustなど)から来た方に向けて、Dart 3のswitch式を使ってResult型をエレガントに料理する方法を、基本から本質まで優しく紐解いていきますね。ここをクリアすれば、あなたのDartの基本はバッチリマスターできますよ!
—
1. そもそも「Result型」ってなぜ必要なの?
普段のプログラミングで、こんなコードを書いたことはありませんか?
// 従来のよくあるスタイル(例外ベース)
try {
final user = fetchUser();
// 処理が続く…
} catch (e) {
// エラーハンドリング
}
例外(Exception)は便利ですが、「どこでどんなエラーが投げるのか」がシグネチャ(関数の型定義)から見えにくく、うっかりキャッチし忘れるとそのままアプリがクラッシュしてしまいますよね。
そこで登場するのが `Result型` です。
Result型とは、「処理が成功した(Data)」か「失敗した(Error)」のどちらかの状態を必ず包み込む、いわば「カプセル」のようなものです。
Dart 3のレコード(Records)でResult型を即席で表現する
Dart 3では、わざわざ大げさなクラスを作らなくても、レコード(Records)という機能を使って軽量なResult型を表現できます。
// 成功時は (data: データの型, error: null)
// 失敗時は (data: null, error: エラーの型)
// …とするより、もっとスマートな方法があります!
Dart 3の強力な武器である「代数的データ型(Sealedクラス)」を組み合わせるのが、最も美しく型安全なアプローチです。早速見ていきましょう!
—
2. Sealedクラスとswitch式で作る「極上のResultパターン」
まずは、成功と失敗を型安全に表現する `Result` を定義します。
// 1. 成功と失敗の設計図(Sealedクラス)
// Dartのコンパイラは、sealedクラスのサブクラスを完全に把握します。
sealed class Result
class Success
final T value;
Success(this.value);
}
class Failure
final Exception error;
Failure(this.error);
}
この `Result
Result さあ、ここからが本番です。受け取った `Result` を、Dart 3のswitch式(Switch Expression)を使って処理します。 従来の `switch文` と違い、switch「式」は値を返します。さらに、Dartのコンパイラは「すべてのパターンが網羅されているか」を静的にチェックしてくれます。 void main() { // 2. switch式で結果をエレガントにハンドリング // 失敗パターン:Failureクラスのerrorを取り出す print(message); 1. 網羅性チェック(Exhaustiveness Checking) — 初学者の開発現場でよく見られる「ハマりどころ」をいくつかピックアップしておきますね。 // ❌ やりがちなミス(switch文のノリで書き換えてしまう) // ⭕ 正しいswitch式(変数に代入する形にする) エラーの詳細な中身が要らない場合は、ワイルドカードを使ってスッキリ書けます。 final statusMessage = switch (result) { — 今回は、Dart 3のswitch式とResult型を組み合わせた、モダンで堅牢なエラーハンドリングの手法を解説しました。 ここをマスターすれば、あなたの書くDartコードは一気にプロダクションクオリティに跳ね上がります。ぜひ、今日の開発から取り入れてみてくださいね。
if (userId <= 0) {
return Failure(Exception('無効なユーザーIDです'));
}
return Success('Alice (ID: $userId)');
}
---
3. 圧倒的な真骨頂!Dart 3の「switch式」による網羅的ハンドリング
final result = fetchUserData(1);
final message = switch (result) {
// 成功パターン:Successクラスのvalueを取り出す
Success(value: final data) => ‘ようこそ、$dataさん!’,
Failure(error: final err) => ‘エラーが発生しました: ${err.runtimeType}’,
};
}このコードの何がスゴいのか?(Dart VMの裏側と知見)
もし `Result` に新しい状態(例えば `Loading` など)を追加し忘れたり、`Failure` の処理を書き忘れたりすると、コンパイルエラーになります。実行時エラーを未然に防ぐ、最強の安全装置です。
2. 変数束縛(Pattern Binding)
`Success(value: final data)` の部分で、カプセルの中身をパターンマッチングで直接変数 `data` にバインディング(抽出)しています。余計なキャスト(`as Success` など)が一切不要で、非常に高速かつ安全に動作します。4. 陥りやすい文法エラーと注意ポイント
① switch「文」と switch「式」の書き間違い
switch (result) {
Success(value: var d) => print(d), // 文脈によってはエラーになる
}
final res = switch (result) {
Success(value: var d) => d,
Failure(error: _) => ‘Default’,
};② ワイルドカードパターン(`_`)の活用
Success() => ‘成功!’,
Failure() => ‘失敗…’, // エラーオブジェクトを取り出さない場合はこれでOK
};5. まとめ
それでは、次の知見でお会いしましょう!バッチリ使いこなしていきましょう!