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

一部のユースケースでは、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");
    }
}

関連項目:

enumOption、および RFC