Grazosi
Grazosi

Reputation: 723

Pattern matching on enum with value inside it?

If I have a enum that imitates an option type, it can either contain some value, or nothing:

enum option {
    some(u8),
    none,
}

Then I can pattern match it like this:

let x = option::some(8);

match x {
    some => println!("some"),
    none => println!("none"),
}

But what if I want to pattern match the value inside the some? Intuitively, I think it would be something like so:

match x {
    some(x) => println!("{}", x),
    none => println!("none"),
}

But Rust has no idea what this is. I also try to see if the some itself is the u8 value:

match x {
    some => println!("{}", some),
    none => println!("none"),
}

This also does not work. How do I get the value inside the enum?

Upvotes: 2

Views: 1985

Answers (2)

Masklinn
Masklinn

Reputation: 42612

Completment to at54321's answer:

Then I can pattern match it like this:

let x = option::some(8);

match x {
    some => println!("some"),
    none => println!("none"),
}

That does not actually work, it will always match the first branch (always print some), and if you read the compiler's warning it'll tell you that:

warning: unreachable pattern
  --> src/main.rs:11:5
   |
10 |     some => println!("some"),
   |     ---- matches any value
11 |     none => println!("none"),
   |     ^^^^ unreachable pattern
   |
   = note: `#[warn(unreachable_patterns)]` on by default

warning: unused variable: `some`
  --> src/main.rs:10:5
   |
10 |     some => println!("some"),
   |     ^^^^ help: if this is intentional, prefix it with an underscore: `_some`
   |
   = note: `#[warn(unused_variables)]` on by default

warning: unused variable: `none`
  --> src/main.rs:11:5
   |
11 |     none => println!("none"),
   |     ^^^^ help: if this is intentional, prefix it with an underscore: `_none`

So it tells you that none is not reachable (because the first branch is a catchall), and it hints that some and none are new bindings, not enum variants.

But what if I want to pattern match the value inside the some? Intuitively, I think it would be something like so:

match x {
    some(x) => println!("{}", x),
    none => println!("none"),
}

If, again, you read the error message, the compiler gives you the solution (though the why is not clear):

error[E0531]: cannot find tuple struct or tuple variant `some` in this scope
   --> src/main.rs:10:5
    |
10  |     some(x) => println!("some"),
    |     ^^^^
    |
help: a tuple variant with a similar name exists
    |
10  |     Some(x) => println!("some"),
    |     ~~~~
help: consider importing this tuple variant
    |
1   | use crate::option::some;
    |

The issue here is that Rust enums are scoped, which you can see from... the creation of the variant. If you use option::some when creating a value, why would the option:: bit be optional when matching it? And the answer's it's not (and in fact it's generally a good idea to include it, in order to avoid risks of collision / ambiguity between matching a variant and creating a new one).

It's also not entirely clear why you're creating an option type when there's one in the standard library, I will say.

Upvotes: 1

at54321
at54321

Reputation: 11866

This should work:

let x = option::some(8);
match x {
    option::some(x) => println!("{}", x),
    option::none => println!("none"),
}

But keep in mind this all-lower-case naming is against the standard Rust naming conventions. Your code will look much better like this:

enum Option {
    Some(u8),
    None
}

pub fn main() {
    let x = Option::Some(8);
    match x {
        Option::Some(x) => println!("{}", x),
        Option::None => println!("none"),
    }
}

You might see that note as nitpicking, but as you add more and more code, that will become a much bigger issue. So it's good to build the right habits from the beginning.

Upvotes: 8

Related Questions