// dictionary
match式.
match式は、対象の値を複数のパターンと上から順に照合し、最初に一致した「アーム」の処理を実行する制御フロー構文です1。if式の分岐条件が論理値型の値に限られるのに対し、match式は列挙型のバリアントやリテラル値など多様なパターンで分岐できます。if式と同じく式であり、実行されたアームの値がmatch式全体の値になります。
enum Ticket {
Standard,
Vip(i32), // 割引率(%)
}
fn describe(ticket: Ticket) -> String {
match ticket {
Ticket::Standard => String::from("通常チケットです"),
Ticket::Vip(discount) => format!("VIPチケット({discount}%引き)"),
}
}
fn main() {
for ticket in [Ticket::Standard, Ticket::Vip(30)] {
println!("{}", describe(ticket));
}
}Playgroundで開くアームとパターン
各アームはパターン => 式,という形で書き、複数のアームを並べます。パターンは上から順に照合され、最初に一致したアームだけが実行されます。C言語のswitchと異なり次のアームへの意図しないフォールスルーは起こらず、1 | 7 => ...のように|区切りで1つのアームに複数パターンをまとめることもできます2。
値を束縛するパターン
パターンの中に変数名を書くと、マッチした値(の一部)をその変数に束縛し、対応するアームの式の中で使えます。上記のTicket::Vip(discount)はその例で、Vipが保持するi32の値がdiscountという名前でアーム内から使えるようになります。
網羅性チェック
match式は対象の型が取りうる値をすべて網羅しなければならず、一致しうる値の中に処理されないものが1つでも残っているとコンパイルエラーになります3。i32のように取りうる値を列挙しきれない型では、任意の値にマッチする包括パターン(_などで書く)を最後に置いて残りをまとめて処理するのが一般的です。
fn describe(n: i32) -> &'static str {
match n {
1 => "one",
2 => "two",
} // エラー: E0004(あり得る値をすべて網羅していない)
}
fn main() {
println!("{}", describe(5));
}Playgroundで開く補足
バリアント追加時に効く網羅性チェック
match式の網羅性チェックは、列挙型にバリアントを追加したときに真価を発揮します。追加後に対応漏れがあるmatch式ではすべてコンパイルエラーが出るため、修正が必要な箇所をコンパイラが教えてくれます。
Footnotes
-
The Rust Reference: Match expressions — マッチ対象の値(scrutinee)を各アームのパターンと順に比較し、最初にマッチしたアームが選ばれると定義しています。 ↩
-
The Rust Reference: Patterns - Or patterns —
|で複数のパターンを1つに結合できると定義しています。 ↩ -
E0004 - Error codes index —
match式が対象の型が取りうるすべての値を網羅していない場合に発生するエラーであると定義しています。 ↩
この辞書が使われているページ
backlinks 9