Rustのmatch
match は、ある値をパターンの一覧と順番に比べて、当てはまったパターンのコードを実行します。ほかの言語の switch 文を使ったことがあれば、それをもっと強力にしたものだと考えてください。使ったことがなくても大丈夫です。早いうちに覚えておくと、とても役に立つ書き方です。
基本的なmatch
Section titled “基本的なmatch”fn main() { let day = 3;
match day { 1 => println!("月曜日"), 2 => println!("火曜日"), 3 => println!("水曜日"), 4 => println!("木曜日"), 5 => println!("金曜日"), _ => println!("週末"), }}実行結果:
水曜日_ は「それ以外すべて」に当てはまるパターンです。上に書いたどのパターンにも当てはまらない値は、ここで受け止められます。match では、ありうるすべての値を処理しなければなりません。そのため、たいていは _ を置いて「それ以外」をまとめて扱います。
複数の値をまとめてマッチする
Section titled “複数の値をまとめてマッチする”| を使うと、いくつかの値を1つのアーム(腕)にまとめられます。
fn main() { let day = 6;
match day { 1 | 2 | 3 | 4 | 5 => println!("平日"), 6 | 7 => println!("週末"), _ => println!("正しい曜日ではありません"), }}範囲でマッチする
Section titled “範囲でマッチする”数値なら、..= を使って範囲をまるごとマッチできます。
fn main() { let score = 85;
match score { 90..=100 => println!("A"), 75..=89 => println!("B"), 60..=74 => println!("C"), _ => println!("F"), }}式としてのmatch
Section titled “式としてのmatch”if と同じように、match も値を返せます。
fn main() { let day = 6;
let kind = match day { 1 | 2 | 3 | 4 | 5 => "平日", 6 | 7 => "週末", _ => "不明", };
println!("{kind}");}テキストや文字でマッチする
Section titled “テキストや文字でマッチする”match は数値専用ではありません。文字列スライス(&str)や文字(char)にも使えます。'a'..='z' のような文字の範囲も、数値の範囲と同じように使えます。
fn main() { let command = "stop"; match command { "start" => println!("開始します..."), "stop" | "quit" => println!("停止します。"), _ => println!("不明なコマンド: {command}"), }
let letter = 'k'; let kind = match letter { 'a' | 'e' | 'i' | 'o' | 'u' => "母音", 'a'..='z' => "子音", '0'..='9' => "数字", _ => "それ以外", }; println!("'{letter}' は{kind}です");
let name = String::from("Ferris"); match name.as_str() { "Ferris" => println!("やあ、カニくん!"), _ => println!("こんにちは、{name}さん!"), }}実行結果:
停止します。'k' は子音ですやあ、カニくん!ここで注目してほしい点が2つあります。
- 順番が大切です。
'a'は'a'..='z'にも含まれますが、母音のアームが先にあるので、母音が子音のアームまで届くことはありません。Rustは、当てはまる最初のアームを必ず選びます。 Stringには.as_str()が必要です。"Ferris"のように引用符で囲んで書いたテキストは&strです。Stringをそのままmatchでこれと比べようとすると、Rustはerror[E0308]: mismatched types ... expected String, found &str(「型が一致しません。Stringを期待していたのに&strが見つかりました」)というエラーで止まります。.as_str()を呼ぶと、Stringを&strとして見られるようになり、パターンと比べられます(2つの違いは文字列のページを見てください)。
マッチは大文字と小文字を区別します。"Stop" は "stop" には当てはまりません。ユーザーが入力したテキストなら、input.to_lowercase().as_str() でマッチするのがよく使われる方法です。
matchとif/elseの使い分け
Section titled “matchとif/elseの使い分け”単純な真偽のチェックなら、どちらでも書けます。でも、分岐が3つ、4つと増えてくると match のほうが有利です。長い else if の連なりより読みやすく、すべてのケースを書いたかどうかもコンパイラが確かめてくれます。一方、「はい/いいえ」の条件が1つだけなら、今でも if/else がぴったりです。
1. 月の日数
Section titled “1. 月の日数”月の番号 month(2)を保存してください。match を式として使ってその月が何日あるかを求め(うるう年は考えなくてかまいません)、2月は28日あります と表示しましょう。ヒント:1、3、5、7、8、10、12月は31日です。| を使って1つのアームにまとめましょう。
解答を見る
fn main() { let month = 2;
let days = match month { 1 | 3 | 5 | 7 | 8 | 10 | 12 => 31, 4 | 6 | 9 | 11 => 30, 2 => 28, _ => 0, // 実在しない月 };
println!("{month}月は{days}日あります");}実行結果:
2月は28日あります2. HTTPステータスコード
Section titled “2. HTTPステータスコード”Webサーバーは数値で返事をします。code を短い意味に変換してください。200 は "OK"、404 は "Not Found"、それ以外の400〜499は "クライアントエラー"、500〜599は "サーバーエラー"、それ以外はすべて "不明" です。503 で試してみましょう。ヒント:404 ちょうどのアームは、400..=499 の範囲の上に書いてください。そうしないと、決してそこまで届きません。
解答を見る
fn main() { let code = 503;
let meaning = match code { 200 => "OK", 404 => "Not Found", // 400..=499 の範囲より前に書く必要がある 400..=499 => "クライアントエラー", 500..=599 => "サーバーエラー", _ => "不明", };
println!("{code}: {meaning}");}実行結果:
503: サーバーエラーmatchは値をパターンと比べて、当てはまったアームを実行します。- ありうるすべての値を処理する必要があります。「それ以外すべて」には
_を使います。 |で値をまとめたり、..=で範囲をマッチしたりできます。&strのテキストやcharの値でもマッチできます。Stringでマッチするには.as_str()を使います。matchもifと同じく、式として値を返せます。
理解度チェック
Section titled “理解度チェック”理解度チェック
1. match式の中で、_ パターンはどんな働きをしますか?
2. match式がありうるすべての値を処理しておらず、_ のアームもない場合はどうなりますか?
3. 1、2、3のような複数の値を1つのアームでマッチするには、どう書きますか?
スコア: 0 / 3
さらに詳しく
Section titled “さらに詳しく”- match制御フロー構造 — The Rust Programming Language 日本語版:公式の章です。列挙型(enum)や
Optionに対するmatchも紹介しています。 - match — Rust by Example 日本語版:値、
|、範囲、_を使った、コンパクトな実行できる例です。 - Range patterns — The Rust Reference(英語):パターンでどの型と、どの形の範囲が使えるのかを正確に説明しています。
- Match expressions — The Rust Reference(英語):アーム、ガード、そして
matchがどのように値を返すかについての正確なルールです。