Rustのif let / while let
これまで Option や Result を扱うのに match を使ってきました。でも実際には、気にしたいパターンは1つだけで、ほかはすべて無視したい、ということがよくあります。何もしないためだけに _ => {} のアームを書いて match を完成させることもできますが、やりたいことに対して大げさです。そんなときの近道が if let です。
matchを全部書くと大げさになる例
Section titled “matchを全部書くと大げさになる例”fn main() { let age: Option<i32> = Some(30);
match age { Some(value) => println!("年齢は{value}歳です"), _ => {}, // このケースは実は気にしていない }}この _ => {} は、「すべてのケースを処理する」という match のルールを満たすためだけにあって、何もしていません。Some のときだけ何かしたいのなら、このコードは考えていることに比べて長すぎます。
if let
Section titled “if let”fn main() { let age: Option<i32> = Some(30);
if let Some(value) = age { println!("年齢は{value}歳です"); }}実行結果:
年齢は30歳ですこれは「もし age が Some(value) というパターンに当てはまるなら、中身を value に入れて、このブロックを実行する」と読みます。age が None なら、ブロックは飛ばされるだけです。エラーにもならず、何も表示されません。
elseを付ける
Section titled “elseを付ける”ふつうの if と同じように、if let にも else を付けられます。
fn main() { let age: Option<i32> = None;
if let Some(value) = age { println!("年齢は{value}歳です"); } else { println!("年齢が指定されていません"); }}Resultでif letを使う
Section titled “Resultでif letを使う”Resultのページで学んだ Result でも、同じように使えます。
fn main() { let input = "42";
if let Ok(number) = input.parse::<i32>() { println!("変換結果: {number}"); } else { println!("数値に変換できませんでした"); }}else if letでつなげる
Section titled “else if letでつなげる”if に else if があるように、if let の後ろにも else if let を続けられます。Rustはパターンを順番に試し、最初に当てはまったブロックを実行します。値を探す場所がいくつかあって、優先順位が決まっているときに便利です。
fn main() { let nickname: Option<&str> = None; let full_name: Option<&str> = Some("フェリス・クラブ");
if let Some(nick) = nickname { println!("やあ、{nick}!"); } else if let Some(name) = full_name { println!("こんにちは、{name}さん。"); } else { println!("こんにちは、どなたか存じませんが。"); }}実行結果:
こんにちは、フェリス・クラブさん。nickname は None なので、最初のブロックは飛ばされます。full_name は Some(name) に当てはまるので、そのブロックが実行され、最後の else にはたどり着きません。else if is_admin { ... } のような、ふつうの条件をチェーンのどこかに混ぜることもできます。
それぞれの変数は、自分のブロックの中にしか存在しません。nick は2つ目のブロックでは使えませんし、name もチェーンが終わった後では使えません。取り出した値をその後のコード全体で使いたいなら、パターンマッチングのページにあるlet-elseを見てみましょう。
while let
Section titled “while let”while let は同じ考え方をループに当てはめたものです。値がパターンに当てはまる間、ループを続けます。コレクションの中身を1つずつ取り出していくときに特に便利です。
fn main() { let mut stack = vec![1, 2, 3];
while let Some(top) = stack.pop() { println!("{top}"); }}実行結果:
321.pop() は、要素が残っている間は Some(value) を返し、ベクタが空になると None を返します。None になった時点で、while let がループを自動的に止めてくれます。長さを自分でチェックする必要はありません。
if letとmatch、どちらを使う?
Section titled “if letとmatch、どちらを使う?”複数のケースをそれぞれ違うやり方で処理したいなら、match を使いましょう。気にしたいパターンが本当に1つだけで、ほかはすべて無視してよいなら、if let の出番です。if let は match の代わりになるものではありません。「1つのアームだけ気にしたい」というよくある場面を、短く書くための方法です。
1. スタックの合計
Section titled “1. スタックの合計”let mut numbers = vec![4, 8, 15]; と、0 から始まる合計 total を用意します。while let と .pop() を使って末尾から数を1つずつ取り出し、それを total に足して、取り出した数と新しい合計を表示してください。ヒント:total には mut が必要です。total += n で足せます。
解答を見る
fn main() { let mut numbers = vec![4, 8, 15]; let mut total = 0;
while let Some(n) = numbers.pop() { total += n; println!("{n}を取り出しました。合計は{total}です"); }}実行結果:
15を取り出しました。合計は15です8を取り出しました。合計は23です4を取り出しました。合計は27です.pop() は末尾から取り出すので、15が最初に出てきます。
2. 文字列から年齢をチェックする
Section titled “2. 文字列から年齢をチェックする”let input = "17"; を用意します。u32 に変換できたら、その年齢が成人(18歳以上)か未成年かを表示してください。変換できなければ、数値ではないと表示します。input を "abc" に変えても試してみましょう。ヒント:if let のブロックの中に、ふつうの if / else を書きます。
解答を見る
fn main() { let input = "17";
if let Ok(age) = input.parse::<u32>() { if age >= 18 { println!("{age}歳は成人です"); } else { println!("{age}歳は未成年です"); } } else { println!("「{input}」は数値ではありません"); }}実行結果:
17歳は未成年ですinput = "abc" にすると変換に失敗し、外側の else が実行されて 「abc」は数値ではありません と表示されます。
if let パターン = 値 { ... }は、値がパターンに当てはまるときだけブロックを実行します。それ以外は何も言わずに飛ばされます。- ふつうの
ifと同じく、elseを付けると当てはまらないケースも処理できます。else if letで複数のパターンをつなげることもできます。 while let パターン = 値 { ... }は、値がパターンに当てはまり続ける間ループします。.pop()でコレクションを空にしていくときに便利です。- 気にするパターンが1つだけなら
if let/while letを、いくつものケースを別々に処理したいならmatchを使いましょう。
理解度チェック
Section titled “理解度チェック”理解度チェック
1. if let Some(value) = age を実行したとき、age が None だとどうなりますか?
2. if let ではなく match を使うべきなのはどんなときですか?
3. while let Some(top) = stack.pop() { ... } のループは、いつ止まりますか?
スコア: 0 / 3
さらに詳しく
Section titled “さらに詳しく”- if letで簡潔な制御フロー — The Rust Programming Language 日本語版:公式の入門です。日本語版にはまだlet-elseの節がないので、let-elseについては英語版の同じ章(英語)を参照してください。
- if let — Rust By Example 日本語版:
Optionや自分で定義したenumを使った実行できるサンプルと、パターンが1つならmatchよりif letが向いている理由がわかります。 - while let — Rust By Example 日本語版:
loopとmatchで書いたループを、短いwhile letに書き直す例です。 if letpatterns — The Rust Reference(英語):if letとmatchの関係も含めた、正確なルールです。