Caution

お使いのブラウザはJavaScriptが実行できない状態になっております。
当サイトはWebプログラミングの情報サイトの為、
JavaScriptが実行できない環境では正しいコンテンツが提供出来ません。
JavaScriptが実行可能な状態でご閲覧頂くようお願い申し上げます。

Rust辞典

  1. トップページ
  2. Rust辞典
  3. match / パターンマッチ

match / パターンマッチ

Rustの『match』式は値を複数のパターンと照合して処理を分岐します。全パターンを網羅しなければコンパイルエラーになるため、漏れのない分岐が保証されます。ガード条件・バインド・範囲パターンなど豊富な機能があります。

構文
// 基本的なmatch式です。全パターンを網羅する必要があります。
match value {
    パターン1 => 式1,
    パターン2 => {
        // 複数行の場合はブロックを使います。
        式2
    }
    _ => デフォルト処理,  // ワイルドカードで残りを受け取ります。
}

// ガード条件(if)を付けることができます。
match n {
    x if x < 0 => println!("負の数"),
    0 => println!("ゼロ"),
    _ => println!("正の数"),
}

// @ でバインド(値を変数に捕捉)します。
match n {
    x @ 1..=10 => println!("1〜10の範囲: {}", x),
    _ => println!("範囲外"),
}

// | でORパターンを書けます。
match c {
    'a' | 'e' | 'i' | 'o' | 'u' => println!("母音"),
    _ => println!("子音"),
}
パターン種類一覧
パターン概要
リテラル(42, "hello", true)値と完全一致したときにマッチします。
変数名(x)任意の値にマッチして変数にバインドします。
_ (ワイルドカード)任意の値にマッチしますがバインドしません。
範囲(1..=5)範囲内の値にマッチします(末尾含む範囲のみ使用可)。
| (OR)複数パターンのいずれかにマッチします。
タプル((x, y))タプルを分解してバインドします。
構造体(Point { x, y })構造体のフィールドを分解します。
列挙型(Some(x), None)enumのバリアントにマッチして内部値を取り出します。
ガード(パターン if 条件)パターン一致後に追加条件を評価します。
@ バインド(x @ 1..=5)パターンマッチしつつ値を変数に束縛します。
.. (残り無視)構造体・タプルの残りのフィールドを無視します。
サンプルコード
#[derive(Debug)]
enum Coin {
    Penny,
    Nickel,
    Dime,
    Quarter(String),  // 州名を持つバリアントです。
}

#[derive(Debug)]
struct Point {
    x: i32,
    y: i32,
}

fn coin_value(coin: Coin) -> u32 {
    match coin {
        Coin::Penny => {
            println!("ラッキーペニー!");
            1
        }
        Coin::Nickel => 5,
        Coin::Dime => 10,
        Coin::Quarter(state) => {
            println!("州: {}", state);
            25
        }
    }
}

fn main() {
    // enumのmatchです。
    println!("--- Coin match ---");
    println!("Penny: {} セント", coin_value(Coin::Penny));
    println!("Quarter: {} セント", coin_value(Coin::Quarter("Alaska".to_string())));

    // 整数の範囲パターンです。
    println!("\n--- 整数の範囲 ---");
    let n = 7;
    match n {
        1 => println!("1です"),
        2 | 3 | 5 | 7 | 11 => println!("素数です"),
        x @ 13..=19 => println!("ティーン: {}", x),
        _ => println!("その他"),
    }

    // タプルの分解です。
    println!("\n--- タプルパターン ---");
    let point = (0, -2);
    match point {
        (0, 0) => println!("原点"),
        (x, 0) | (0, x) => println!("軸上: {}", x),
        (x, y) if x == y => println!("対角線上: ({}, {})", x, y),
        (x, y) => println!("一般点: ({}, {})", x, y),
    }

    // 構造体の分解です。
    println!("\n--- 構造体パターン ---");
    let p = Point { x: 3, y: 0 };
    match p {
        Point { x, y: 0 } => println!("x軸上: x={}", x),
        Point { x: 0, y } => println!("y軸上: y={}", y),
        Point { x, y } => println!("一般点: ({}, {})", x, y),
    }

    // Option のパターンマッチです。
    println!("\n--- Option ---");
    let opt: Option<i32> = Some(42);
    match opt {
        Some(x) if x > 0 => println!("正の値: {}", x),
        Some(x) => println!("非正の値: {}", x),
        None => println!("値なし"),
    }
}
概要

『match』はRustの中心的な機能の一つです。コンパイラが全パターンの網羅性(exhaustiveness)を検査するため、新しいバリアントを追加したときに対応漏れをコンパイル時に検出できます。

単純なOption/Resultのパターンマッチにはmatchではなく『if let』や『while let』を使うとより簡潔に書けます。

matchの各アーム(パターン => 式)はカンマで区切ります。ブロック({ })を使う場合はカンマを省略できます。

条件分岐の基本は『if / else / if let』を参照してください。

記事の間違いや著作権の侵害等ございましたらお手数ですがまでご連絡頂ければ幸いです。