ChatGPT解决这个技术问题 Extra ChatGPT

How to match a String against string literals?

I'm trying to figure out how to match a String in Rust.

I initially tried matching like this, but I figured out Rust cannot implicitly cast from std::string::String to &str.

fn main() {
    let stringthing = String::from("c");
    match stringthing {
        "a" => println!("0"),
        "b" => println!("1"),
        "c" => println!("2"),
    }
}

This has the error:

error[E0308]: mismatched types
 --> src/main.rs:4:9
  |
4 |         "a" => println!("0"),
  |         ^^^ expected struct `std::string::String`, found reference
  |
  = note: expected type `std::string::String`
             found type `&'static str`

I then tried to construct new String objects, as I could not find a function to cast a String to a &str.

fn main() {
    let stringthing = String::from("c");
    match stringthing {
        String::from("a") => println!("0"),
        String::from("b") => println!("1"),
        String::from("c") => println!("2"),
    }
}

This gave me the following error 3 times:

error[E0164]: `String::from` does not name a tuple variant or a tuple struct
 --> src/main.rs:4:9
  |
4 |         String::from("a") => return 0,
  |         ^^^^^^^^^^^^^^^^^ not a tuple variant or struct

How to actually match Strings in Rust?

stringthing.as_str() is probably the most straightforward of all the answers; I don't like as_ref because it's unnecessarily general, which can lead to bugs, and not as explicit, it isn't completely clear that as_ref() is going to be a &str, as_str is simple and clear.
@Zorf You are right. The answer was accepted when as_str did not exist yet. I changed the accepted answer but thank all people who answered this question!

m
mcherm

UPDATE: Use .as_str() like this to convert the String to an &str:

match stringthing.as_str() {
    "a" => println!("0"),
    "b" => println!("1"),
    "c" => println!("2"),
    _ => println!("something else!"),
}

Reason .as_str() is more concise and enforces stricter type checking. The trait as_ref is implemented for multiple types and its behaviour could be changed for type String, leading to unexpected results. Similarly, if the input argument changes type, the compiler will not signal a problem when that type implements the trait as_ref.

The docs suggest to use as_str as well https://doc.rust-lang.org/std/string/struct.String.html, https://doc.rust-lang.org/std/primitive.str.html

Old answer:

as_slice is deprecated, you should now use the trait std::convert::AsRef instead:

match stringthing.as_ref() {
    "a" => println!("0"),
    "b" => println!("1"),
    "c" => println!("2"),
    _ => println!("something else!"),
}

Note that you also have to explicitly handle the catch-all case.


using rust 1.4.0 one can use the trim() function. Just using as_ref() doesn't match the string.
I think the match fails because of whitespace that trim() removes. This is nice for deferencing to match against user input.
It doesn't work. It can only match _ if I get String from read_line.
Don't know much about how rust manages different types of strings, but it seems to work on a basic example.
@MaskedMan read_line reads a line. Lines end in \n. .trim_end() (or, more precisely, trim_end_matches('\n')) will remove that for you.
S
Shepmaster

You can do something like this:

match &stringthing[..] {
    "a" => println!("0"),
    "b" => println!("1"),
    "c" => println!("2"),
    _ => println!("something else!"),
}

There's also an as_str method as of Rust 1.7.0:

match stringthing.as_str() {
    "a" => println!("0"),
    "b" => println!("1"),
    "c" => println!("2"),
    _ => println!("something else!"),
}

S
Shepmaster

You could also do

match &stringthing as &str {
    "a" => println!("0"),
    "b" => println!("1"),
    "c" => println!("2"),
    _ => println!("something else!"),
}

See:

std::string::String

std::ops::Deref

Deref coercions


This is effectively the same as .as_str() and that is way shorter.
".as_str()" is literally 1 more character than "as &str" though? am I missing something? @amyiris
S
Shepmaster

Editor's note: This answer pertains to an version of Rust before 1.0 and does not work in Rust 1.0

You can match on a string slice.

match stringthing.as_slice() {
    "a" => println!("0"),
    "b" => println!("1"),
    "c" => println!("2"),
    _ => println!("something else!"),
}

better to use .as_ref() or .as_str(), both did not take ownership.
o
omrihhh

You can try:

fn main() {
    let stringthing = String::from("c");
    match &*stringthing {
        "a" => println!("0"),
        "b" => println!("1"),
        "c" => println!("2"),
        _ => println!("else")
    }
}

It might improve the usefulness of your answer if you explain what &*stringthing means and does.
u
u_mulder

You can convert the String into &str by doing this:

fn main() {
    let stringthing = String::from("c");
    match &stringthing[..] {
        "a" => println!("0"),
        "b" => println!("1"),
        "c" => println!("2"),
    }
}

r
rujen gelal

Use as_str() on Strings to get string slice

fn main() {
    let stringthing = String::from("c");
    match stringthing.as_str() {
        String::from("a") => println!("0"),
        String::from("b") => println!("1"),
        String::from("c") => println!("2"),
    }
}

if your taking input from the console and want to perform match on it be sure to call trim() after as_str() to remove escape character i.e '\n' from the input. As in

match stringthing.as_str().trim() {...}