## Keyboard shortcuts

Press `←` or `→` to navigate between chapters

Press `S` or `/` to search in the book

Press `?` to show this help

Press `Esc` to hide this help

# if let

列挙型をマッチさせるとき、場合によっては`match`を使用すると不自然な書き方になってしまう場合があります。例えば

    #![allow(unused)]
    fn main() {
    // `optional`という変数の型を`Option<i32>`に指定。
    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);
        }

        // デストラクトした結果が`Some()`にならない場合の処理を明示したい場合、
        // `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 {
            // 今回は`else if`の評価がfalseなので、このブロック内がデフォルト。
            println!("I don't like letters. Let's go with an emoticon :)!");
        }
    }

同様に`if let`は任意の列挙型のマッチに使えます。

    // 列挙型の例
    enum Foo {
        Bar,
        Baz,
        Qux(u32)
    }

    fn main() {
        // 変数の作成
        let a = Foo::Bar;
        let b = Foo::Baz;
        let c = Foo::Qux(100);

        // 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 Foo::Qux(value @ 100) = c {
            println!("c is one hundred");
        }
    }

もう一つのメリットは`if let`がパラメータを持たない列挙型にも使えることです。列挙型が`PartialEq`を実装または導出していなくても問題ありません。その場合、列挙型のインスタンスは比較できないので`if Foo::Bar == a`はコンパイルエラーとなりますが、`if let`は引き続き使えます。

試してみましょう。以下の例を`if let`を使って直してみてください。

    // この列挙型はPartialEqを実装も導出もしていません。
    // そのためFoo::Bar == aはエラーとなります。
    enum Foo {Bar}

    fn main() {
        let a = Foo::Bar;

        // Foo::Barにマッチする変数
        if Foo::Bar == a {
        // ^-- ここでコンパイルエラー。`if let`を使ってみましょう。
            println!("a is foobar");
        }
    }

### 参照

列挙型, `Option`, RFC