if let
一部のユースケースでは、enum をマッチする際に match は扱いにくくなります。例:
#![allow(unused)] fn main() { // `Option<i32>` 型の `optional` を作成する let optional = Some(7); match optional { Some(i) => println!("This is a really long string and `{:?}`", i), _ => {}, // ^ `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"); } }
もう 1 つの利点は、if let によってパラメーターを持たない enum バリアントをマッチできることです。これは、enum が PartialEq を実装または derive していない場合でも当てはまります。そのような場合、enum のインスタンス同士を等価比較できないため if Foo::Bar == a はコンパイルに失敗しますが、if let は引き続き機能します。
挑戦してみますか? 次の例を修正して if let を使用してください。
// この enum は意図的に PartialEq を実装も derive もしていません。 // そのため、以下の 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"); } }