if let
enumをマッチする時、しばしばmatchは冗長です。例えば
#![allow(unused_variables)] fn main() { // `Option<i32>`型の`optional`を作成する let optional = Some(7); match optional { Some(i) => { println!("This is a really long string and `{:?}`", i); // これは本当に長い文字列で、`{:?}`です // ^ iをoptionから分割代入しているので、2つインデントが必要です。 }, _ => {}, // ^ `match`はすべてを網羅しないといけないため、必要です。 // 無駄だと思いませんか? }; }
if letはこの場合おいて簡潔な上、失敗時の処理も柔軟にできます。
fn main() { // すべて`Option<i32>`型です let number = Some(7); let letter: Option<i32> = None; let emoticon: Option<i32> = None; // `if let`は、「もし`let`が`number`を分解した // 結果が`Some(i)`なら、ブロックを実行する。」 // という意味です。 if let Some(i) = number { println!("Matched {:?}!", i); // {:?}にマッチしました! } // もし失敗を扱いたければ、elseを使います。 if let Some(i) = letter { println!("Matched {:?}!", i); } else { // 分解に失敗した時、このブロックを実行します。 println!("Didn't match a number. Let's go with a letter!"); // 数字にマッチしませんでした。文字で行きましょう! } // もう一つ失敗したときの処理を作る let i_like_letters = false; if let Some(i) = emoticon { println!("Matched {:?}!", i); // 失敗した時、`else if`の条件を見て、分岐します。 } else if i_like_letters { println!("Didn't match a number. Let's go with a letter!"); } else { // 条件がfalseの時、この枝を実行します。 println!("I don't like letters. Let's go with an emoticon :)!"); // 文字は嫌いです。絵文字で行きましょう :) } }
同じように、if letはすべてのenumで使えます。
// 例で使うenum enum Foo { Bar, Baz, Qux(u32) } fn main() { // 例で使う変数 let a = Foo::Bar; let b = Foo::Baz; let c = Foo::Qux(100); // 変数aはFoo::Barにマッチする if let Foo::Bar = a { println!("a is foobar"); } // 変数bはFoo::Barにマッチしないので、 // 何も出力しない。 if let Foo::Bar = b { println!("b is foobar"); } // 変数cは値を持つFoo::Quxにマッチし、 // 前の例のSome()と同じような挙動をする。 if let Foo::Qux(value) = c { println!("c is {}", value); } // `if let`でも束縛は使えます。 if let Foo::Qux(value @ 100) = c { println!("c is one hundred"); } }
もう一つのif letの恩恵は、enumのパラメータなしの列挙子にマッチできることです。enumはPartialEqを実装も継承もしないため、enumのインスタンスは比較できず、
if Foo::Bar == a はコンパイルに失敗しますが、 if letで同じことができます。
挑戦しますか? 次の例をif letを使うように修正してください。
// このenumはPartialEqを実装も継承もしません。 // よって、下のFoo::Bar == aは失敗します。 enum Foo {Bar} fn main() { let a = Foo::Bar; // 変数aはFoo::Barにマッチします if Foo::Bar == a { // ^-- この節はコンパイルエラーを起こします。代わりに`if let`を使ってください。 println!("a is foobar"); } }