【入門編】Dart 3のパターンマッチングで実装する「Result型」:例外処理を型安全なフローに変える – Dart コア文法・オブジェクト指向・Null安全解析バイブル

やあ。Dartの世界へようこそ。
Dart 3で導入されたパターンマッチングは、単なる「便利な構文」だと思っていませんか?実はこれ、Dartの型システムを一段上の次元へ引き上げるための革命的なツールなんです。

今日は、多くの開発者が頼りがちな `try-catch` という「例外のジャングル」から抜け出し、Dart 3のパターンマッチングを使って、堅牢で美しい `Result型` を構築する方法を伝授します。

—

1. なぜ `try-catch` ではなく `Result型` なのか?

プログラミングにおいて、例外(Exception)は「予期せぬ事態」に使うべきものです。しかし、ネットワークの切断やバリデーションエラーなど、「起こりうるのが前提の失敗」まで `try-catch` で処理すると、コードのフローが分断され、可読性が著しく低下します。

そこで登場するのが `Result型` です。これは「成功なら値」「失敗ならエラー」という二つの状態を型として持ち歩く手法です。

概念図:分岐の美学

  • 従来の `try-catch`: 正常系がメインで、異常系が「横から割り込む(goto的)」
  • Result型 + パターンマッチング: 正常系と異常系が「対等な選択肢」として扱われ、コンパイラが漏れを許さない

—

2. 究極のResult型を実装する

まずは、このシンプルな `Result` クラスを見てください。`sealed` クラスを使うのがポイントです。

// sealed class にすることで、コンパイラは「このクラスを継承できるのはこのファイルだけ」と理解し、
// パターンマッチングの網羅性をチェックできるようになります。
sealed class Result {
const Result();
}

class Success extends Result {
final T value;
const Success(this.value);
}

class Failure extends Result {
final Exception error;
const Failure(this.error);
}

この `sealed` というキーワードが重要です。これを使うことで、Dartのコンパイラは「Resultには `Success` か `Failure` しか存在しない」ことを完璧に保証します。

—

3. パターンマッチングでフローを掌握する

では、実際にこの `Result` を使ってみましょう。Dart 3の `switch` 式を使えば、驚くほど直感的にハンドリングできます。

Result fetchUserData() {
// ここではシミュレーションとして成功を返します
return Success(“Dartマスターへの道”);
}

void main() {
final result = fetchUserData();

// switch式でパターンマッチング!
// もし Success か Failure の片方を書き忘れると、コンパイラがエラーを出してくれます。
final message = switch (result) {
Success(value: final v) => “成功しました: $v”,
Failure(error: final e) => “失敗しました: ${e.toString()}”,
};

print(message);
}

ここがポイント!

  • `switch` 式: 値を返すことができます。if-elseのネストに悩まされる必要はもうありません。
  • パターン分解: `Success(value: final v)` と書くことで、`Success` クラスの中にある `value` を直接取り出しています。これを「デストラクト(分解)」と呼びます。

—

4. 初学者が陥りやすい「罠」と対策

ここをクリアすれば、Dart 3の使い手として一歩先へ行けますよ。

罠1:網羅性チェック(Exhaustiveness checking)のエラー

`switch` を書いたとき、「’Result’ 型のすべてのケースを処理していません」というエラーが出ることがあります。これはDartからの「お節介」ではなく「愛」です。
対策: `sealed` クラスを使っている限り、必ず全パターン(SuccessとFailure)を記述してください。もし不要なケースがあっても `_ => …` でハンドルしましょう。

罠2:型推論の迷子

`Result` を使う際、ジェネリクスを省略すると `Result` になってしまい、型安全性が崩れます。
対策: 可能であれば明示的に型を宣言するか、関数から戻る型を明確に定義する癖をつけましょう。

—

5. 最後に:コードの「重み」を感じるということ

`try-catch` を多用するコードは、実行時に「何が起きるか分からない」という不安を抱えたまま走ります。一方、`Result` 型とパターンマッチングで構築されたコードは、コンパイルの時点で実行経路がすべて証明されています。

Dart VMは、この `sealed` クラスとパターンマッチングの構造を最適化し、非常に高速な分岐処理へと変換します。これは単に書きやすいだけでなく、マシンにとっても理解しやすいコードなのです。

さあ、あなたの次のプロジェクトでは、例外を「投げる」のではなく、結果を「返す」設計に挑戦してみてください。ここをクリアすれば、あなたはもうDartの基本を完全に掌握したと言っても過言ではありませんよ。

また何か疑問があれば、いつでも聞いてくださいね。一緒に最高峰のコードを書いていきましょう!

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