4

Problem description

I'm trying to match option string with match statement

let option_string = Some(String::from("Bob"));
    
match option_string {
  Some("Mike") => false,
  Some("Bob") => true,
  _ => false,
}

And, obviously, got an error expected struct 'String, found '&str'.

I tried to change it into string cast

Some("Mike".to_string()) => false

// Or
Some(String::from("Mike")) => false

But faced with a different error: 'fn' calls are not allowed in patterns


The only working way is to place Mike into a variable before Some

let mike = String::from("Mike");

// and in match
Some(mike) => true,

Question

There is a more elegant way to match String but not string literals in match cases with Option value?

I found the answer but it doesn't look elegant enough too. But is it only one possible way to not create extra variables or functions?

MadMed677
  • 63
  • 3

1 Answers1

6
let mike = String::from("Mike");

// and in match
Some(mike) => true,

This one is actually a misconception, I'm afraid. Variables are not allowed on the left side of a match expression. Having a name on the left side actually creates a new variable that contains the matched content. So the mike variable in your match clause matches everything and then carries the matched String; it is not the same variable as the outer mike variable.

Pay attention to this code example:

fn main() {
    let option_string = Some(String::from("Bob"));

    // Note how this line gets the compiler warning "unused variable".
    // You could leave this line out completely and it would still
    // compile.
    let mike = String::from("Mike");

    let result = match option_string {
        Some(mike) => {
            println!("Matched 'Mike': {}", mike);
            true
        }
        _ => false,
    };

    println!("{:?}", result);
}
Matched 'Mike': Bob
true

In general, you can only match against compile time constants. If you want to compare two variables, you have to use if instead.


Solution

That said, your first example is quite easy to fix:

fn main() {
    let option_string = Some(String::from("Bob"));

    let result = match option_string.as_deref() {
        Some("Mike") => false,
        Some("Bob") => true,
        _ => false,
    };

    println!("{:?}", result);
}
true

Note the .as_deref(), which borrows an Option<&str> from the Option<String>, making it compatible with the string literal match expressions.

Finomnis
  • 18,094
  • 1
  • 20
  • 27