Rust Lang: What is "if let Some(x) = x" doing?

Viewed 1455

I'm working on a rust project written a couple of years ago, and have come across this piece of code, which is literally:

let mut values = vec![];
for x in maybe_values {
    if let Some(x) = x {
        values.push(Arc::new(x));
    }
}

I understand that "if let" introduces a pattern-matching if (Which seems to be a poor re-use of the keyword "let", but I will get over that - If anyone can help me with a mental mnemonic to make sense of "let" here, please do!).

But what is the test Some(x) = x doing?

From my testing, it seems to be a trick/idiom to both a) test that the loop variant 'x' is Some(), and also b) end up with the unwrap()ped value in x.

But I can't fully explain it to myself, and can't find reference to this being an idiom anywhere.

Hope you can help my Rust education path. Thanks.

2 Answers

This is a shorthand for using a full match statement when you only care about matching a single use case.

So this block of code:

if let x = y {
   foo();
} else {
   bar();
}

Is equivalent to using a full match:

match y {
    x => {
        foo();
    }
    _ => {
        bar();
    }
}

For your specific case, it is equivalent to this. The inner x uses the same name as the outer variable which can be confusing, but they are two separate values.

let mut values = vec![];
for x in maybe_values {
    match x {
        Some(y) => values.push(Arc::new(y)),
        _ => {},
    }
}

There are two completely different variables in play here. It's equivalent to.

let mut values = vec![];
for x_1 in maybe_values {
  if let Some(x_2) = x_1 {
    values.push(Arc::new(x_2));
  }
}

In Rust, the right-hand side of a let is evaluated with the left-hand variable not in scope, so when the if let is evaluated, the outer x is still in-scope. Then, if it's a Some value, we make a new variable x which contains the inside of the Option. This variable shadows the previous x, making it inaccessible inside the if statement (in the same way that a function argument called x would render a global variable named x inaccessible by shadowing).

Related