blog.dopana

Back

match は安全で強力な網羅性チェックを提供しますが、特定の1つのパターンのみに関心があり、他のすべてのケースを無視したい場合があります。そのような場面で _ => () を含む match 式を書くのは、冗長なボイラープレートコードになりがちです。

Rustでは、こうしたケースをより簡潔に記述するための構文として if let が用意されています。

10歳でもわかる説明(ELI5):中身がわからないプレゼント箱#

中身がわからないプレゼント箱を想像してみてください:

  • 箱の中にはおもちゃが入っているか(Some(toy))、あるいは完全に空っぽ(None)です。
  • あなたはおもちゃが入っているときだけ取り出して遊びたいと考えています。空っぽの場合は何もせずその場を離れるだけです。
graph TD
    Input["入力値 (Option / Enum)"] --> Check{"指定したパターンに一致?"}
    Check -- はい --> Bind["値を抽出して if let ブロックを実行"]
    Check -- いいえ --> ElseCheck{"else ブロックはある?"}
    ElseCheck -- はい --> ElseAction["else ブロックを実行"]
    ElseCheck -- いいえ --> Ignore["無視して処理を継続"]

matchif let の比較#

設定値が Some(u8) の場合のみ値を出力したいケースを考えます:

match を使った場合(冗長)#

src/main.rs
let config_max = Some(3u8);

match config_max {
    Some(max) => println!("設定された最大値は {max} です"),
    _ => (), // 網羅性を満たすために必須のボイラープレート
}
rust

if let を使った場合(簡潔)#

src/main.rs
let config_max = Some(3u8);

if let Some(max) = config_max {
    println!("設定された最大値は {max} です");
}
rust

[!TIP] if let は、1つのパターンに一致したときだけ処理を行い、それ以外を無視するような match 式の糖衣構文(Syntax Sugar)と考えることができます。

if letelse の組み合わせ#

if let には else ブロックを組み合わせることも可能です(これは match 式の _ => ... アームと同等の挙動になります):

比較:if let と通常の if の違い#

Rust初心者がよく疑問に思うのは、「通常の if 文があるのに、なぜ if let が必要なのか?」という点です。

その決定的な違いは、パターンマッチングとデータ抽出(分配束縛) にあります:

src/main.rs
let score = Some(95);

// 1. 通常の `if` を使用:真偽値(true/false)の評価のみ
if score.is_some() {
    // 内部の値を取り出すために手動で unwrap が必要 -> 冗長かつ危険
    let val = score.unwrap();
    println!("スコア: {val}");
}

// 2. `if let` を使用:パターンの照合と安全な変数束縛を1ステップで実行
if let Some(val) = score {
    println!("スコア: {val}"); // 完全に安全。unwrap() の呼び出しは不要
}
rust
graph TD
    subgraph IfOrdinary ["通常の if"]
        Cond["Boolean条件(true/false)を評価"] --> Unsafe["内部データ取得に手動 unwrap が必要"]
    end
    subgraph IfLet ["if let"]
        Pattern["パターンマッチング"] --> Safe["自動的にデータを抽出し安全にローカル変数へ束縛"]
    end

ifif letmatch の使い分け#

評価軸通常の ifif letmatch
条件の判定対象真偽値式(bool一致対象のパターン(Pattern)あり得るすべてのパターン
データの抽出不可(手動 unwrap が必要)可能(自動で値を取り出して束縛)可能(アームごとに安全に束縛)
網羅性チェックなしなし(単一パターンのみ)あり(100%全ケースの網羅を強制)
分岐数1 (if) または 2 (if/else)1 (if let) または 2 (if let/else)任意(複数アーム)
最適な用途数値の大小比較、論理フラグ判定Option や Enum から1つのバリアントを取り出す複数パターンの分岐、複雑な状態遷移

[!WARNING] if let を採用すると、match が提供するコンパイラの厳格な網羅性チェックを手放すことになります。将来的にEnumのバリアントが追加された際に処理漏れが生じないか留意してください。

まとめ#

  • if let は単一パターンの一致判定とデータ抽出を簡潔に書くための構文です。
  • 必要に応じて else を追加し、不一致時の処理を記述できます。
  • match の冗長なボイラープレートを排除したい場合に有効です。

参考文献#