if let - Rust By Example
Description: A description

# if let

For some use cases, when matching enums, `match` is awkward. For example:

    #![allow(unused_variables)]
    fn main() {
    // Make `optional` of type `Option<i32>`
    let optional = Some(7);

    match optional {
        Some(i) => {
            println!("This is a really long string and `{:?}`", i);
            // ^ Needed 2 indentations just so we could destructure
            // `i` from the option.
        },
        _ => {},
        // ^ Required because `match` is exhaustive. Doesn't it seem
        // like wasted space?
    };

    }

`if let` is cleaner for this use case and in addition allows various failure options to be specified:

    fn main() {
        // All have type `Option<i32>`
        let number = Some(7);
        let letter: Option<i32> = None;
        let emoticon: Option<i32> = None;

        // The `if let` construct reads: "if `let` destructures `number` into
        // `Some(i)`, evaluate the block (`{}`).
        if let Some(i) = number {
            println!("Matched {:?}!", i);
        }

        // If you need to specify a failure, use an else:
        if let Some(i) = letter {
            println!("Matched {:?}!", i);
        } else {
            // Destructure failed. Change to the failure case.
            println!("Didn't match a number. Let's go with a letter!");
        }

        // Provide an altered failing condition.
        let i_like_letters = false;

        if let Some(i) = emoticon {
            println!("Matched {:?}!", i);
        // Destructure failed. Evaluate an `else if` condition to see if the
        // alternate failure branch should be taken:
        } else if i_like_letters {
            println!("Didn't match a number. Let's go with a letter!");
        } else {
            // The condition evaluated false. This branch is the default:
            println!("I don't like letters. Let's go with an emoticon :)!");
        }
    }

In the same way, `if let` can be used to match any enum value:

    // Our example enum
    enum Foo {
        Bar,
        Baz,
        Qux(u32)
    }

    fn main() {
        // Create example variables
        let a = Foo::Bar;
        let b = Foo::Baz;
        let c = Foo::Qux(100);

        // Variable a matches Foo::Bar
        if let Foo::Bar = a {
            println!("a is foobar");
        }

        // Variable b does not match Foo::Bar
        // So this will print nothing
        if let Foo::Bar = b {
            println!("b is foobar");
        }

        // Variable c matches Foo::Qux which has a value
        // Similar to Some() in the previous example
        if let Foo::Qux(value) = c {
            println!("c is {}", value);
        }

        // Binding also works with `if let`
        if let Foo::Qux(value @ 100) = c {
            println!("c is one hundred");
        }
    }

Another benefit: `if let` allows to match enum non-parameterized variants, even if the enum doesn't `#[derive(PartialEq)]`, neither we implement `PartialEq` for it. In such case, classic `if Foo::Bar==a` fails, because instances of such enum are not comparable for equality. However, `if let` works.

Would you like a challenge? Fix the following example to use `if let`:

    // This enum purposely doesn't #[derive(PartialEq)],
    // neither we implement PartialEq for it. That's why comparing Foo::Bar==a fails below.
    enum Foo {Bar}

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

        // Variable a matches Foo::Bar
        if Foo::Bar == a {
        // ^-- this causes a compile-time error. Use `if let` instead.
            println!("a is foobar");
        }
    }

### See also:

`enum`, `Option`, and the RFC