1

When an option variable is known to be non-None, its normally fine to write:

let var = option_var.unwrap();

In one case I ran into, this caused an error about moving out of borrowed context.

if let Some(var) = option_var { ... }

(Handy since it allows Some(ref mut var) = option_var too).

This works, however in this case I don't want this to be an if statement. Writing let Some(var) = option_var; fails with the error "pattern None not covered".

To be clear this question isn't about borrowed context.

Can the let Some(var) = option; syntax be used in a situation where it's known that it's not None? Resolving the "Pattern None not covered" warning? Or is this simply not supported outside an if statement?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
ideasman42
  • 42,413
  • 44
  • 197
  • 320
  • 3
    "In one case I ran into" what's that case? – Ven Jan 10 '17 at 16:39
  • 1
    Or a duplicate of http://stackoverflow.com/q/30463490/155423; http://stackoverflow.com/q/30365055/155423; or any of the [**105 other** questions about "cannot move out of borrowed content"](http://stackoverflow.com/search?q=is%3Aq+%5Brust%5D+cannot+move+out+of+borrowed). Too bad there's not enough detail present here to pick a better duplicate. – Shepmaster Jan 10 '17 at 16:48
  • This question isn't about borrowed context, its about using `let Some(var) = option_var` - if it's possible outside an if statement. – ideasman42 Jan 10 '17 at 16:51
  • 2
    Possible duplicate of http://stackoverflow.com/questions/34953711/unwrap-inner-type-when-enum-variant-is-known ? And the answer is: no you can't use the syntax... luckily in the case of `Option` you have `unwrap()` at your fingertips. Why not use that? – Lukas Kalbertodt Jan 10 '17 at 17:00
  • @LukasKalbertodt stackoverflow.com/questions/34953711 is quite a vague question, the answer to that isn't a direct answer to this question so don't think its a duplicate. This question is direct - *"can a 'let Some(var) = option_var;' expression be used outside an if statement - yes or no"*, if the answer is no, then thats all I wanted to know. I asked this because the warning doesn't explicitly state that that its not supported, which made me think if I knew the right way to write it - it could be made to work. – ideasman42 Jan 10 '17 at 17:05
  • How are you getting a warning for `let Some(var) = option;`? I receive an error for the refutable pattern. – Lee Jan 10 '17 at 17:22
  • It gives an error, corrected the question. – ideasman42 Jan 10 '17 at 17:39

2 Answers2

8

Given the following case:

fn main() {
    let foo = Some(1);
    let Some(bar) = foo;
}

error[E0005]: refutable pattern in local binding: None not covered

let Some(x) = y introduces a pattern; let and match statements and function arguments are pattern-matching contexts, but since in this case the pattern doesn't cover the other possible case, it is not a valid pattern matching context.

The only contexts which the let Some(x) = y statement is applicable to are the if let expressions and while let loops.

If you are sure (e.g. with an earlier assert!() or if it is introduced "by hand") that a None is not possible, you can just use unwrap().

ljedrz
  • 20,316
  • 4
  • 69
  • 97
  • Re: *"but since in this case the pattern doesn't cover the other possible case, it is not a valid pattern matching context."* - is it possible to satisfy this constraint? or does it *require* being used with `if let ... etc` under every circumstance? – ideasman42 Jan 10 '17 at 17:37
  • *The only contexts which the `let Some(x) = y` statement is applicable to are the `if let` expressions and `while let` loops.* This is true for `Option` but not true in general. In general, the pattern passed to `let` must be irrefutable. For Option, since it has two variants, the `Some(_)` pattern is refutable, this requires testing via `if let`. If we consider an enum with only one variant, regular `let Variant(_) = some_enum;` will work fine. – Arnavion Jan 10 '17 at 18:07
6

I've just encountered a similar problem with enum like:

let SomeEnum::First(first) = item;

I know item is SomeEnum::First. But Rust won't let me compile.

One way to bypass this problem is to use a macro like this:

    macro_rules! unwrap {
        ($enum:path, $expr:expr) => {{
            if let $enum(item) = $expr {
                item
            } else {
                panic!()
            }
        }};
    }

And you can invoke unwrap! like this:

let first = unwrap!(SomeEnum::First, item);

PS. I'm using this in my tests. It helps shorten the tests.

Tanin
  • 1,853
  • 1
  • 15
  • 20