Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Matching string in Rust [duplicate]

I'm new to Rust (1.31) and I would like to understand a simple piece of code that does not compile:

fn main() {
    s = String::from("foo");
    match s {
        "foo" => {
            println!("Yes");
        }
        _ => {
            println!("No");
        }
    }
}

The error associated is :

10 |         "foo" => {                                                                                 
   |         ^^^^^ expected struct `std::string::String`, found reference

After this error, I decided to change the code to :

fn main() {
    let s = String::from("foo");

    match s {
        String::from("foo") => {
            println!("Yes");
        }
        _ => {
            println!("No");
        }
    }
}

By doing so, I was hoping to have the correct type, but it is not the case :

10 |         String::from("foo") => {                                                                   
   |         ^^^^^^^^^^^^^^^^^^^ not a tuple variant or struct

I am quite puzzled with this message from the compiler, at the end I managed to make it work by implementing :

fn main() {
    let s = String::from("foo");

    match &s as &str {
        "foo" => {
            println!("Yes");
        }
        _ => {
            println!("No");
        }
    }
}

However, I do not understand the underlying mechanisms that make this solution the right one and why my second example does not work.

like image 274
Nathan Avatar asked Dec 22 '18 21:12

Nathan


People also ask

How do you match strings in Rust?

To conclude, string comparison is quite easy in Rust. The only thing you have to do is convert the string literal into &str. Then you will be able to match a string against a string literal.

Does Rust have pattern matching?

Patterns are a special syntax in Rust for matching against the structure of types, both complex and simple. Using patterns in conjunction with match expressions and other constructs gives you more control over a program's control flow.

How does match work in Rust?

Rust has an extremely powerful control flow construct called match that allows you to compare a value against a series of patterns and then execute code based on which pattern matches.

What is the difference between string and &str in Rust?

In easy words, String is datatype stored on heap (just like Vec ), and you have access to that location. &str is a slice type. That means it is just reference to an already present String somewhere in the heap. &str doesn't do any allocation at runtime.


1 Answers

The first example doesn't work, because s is of type String, which is a string variant that owns the data in it. It is matched against a string literal (which can be be used as type &str). match doesn't understand how to compare those two different types, so it errors.

However String dereferences to &str, by implementing Deref<Target=str>, which means references to String can be used where a &str is required, e.g. for comparing it to one. That's what happens in the third example. By creating the reference &s, the implicit deref can happen, and the two types get comparable.

You can achieve the same thing with a little less magic by using the explicit method which creates a &str from String:

fn main() {
    let s = String::from("foo");

    match s.as_str() {
        "foo" => {
            println!("Yes");
         },
         _ => {
             println!("No");
         }
    }
}

The second example tries to make things comparable making String the common type instead of &str. It doesn't work, because match expects a pattern on the left side, and not a function call which creates a new struct (and which also allocates behind the scene). Even if it would work (e.g. by moving the String creation outside of the match), the approach would be less desirable, because the new String would require a memory allocation.

like image 57
Matthias247 Avatar answered Oct 22 '22 17:10

Matthias247