456

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?

3
  • 9
    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. Commented Jan 10, 2020 at 21:00
  • @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! Commented Jan 10, 2020 at 21:04
  • Is it possible if I have Result<String, Error>? I want to match env::var directly. Commented Nov 5, 2024 at 10:38

9 Answers 9

441

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.

Sign up to request clarification or add additional context in comments.

8 Comments

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.
|
198

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!"),
}

Comments

26

You could also do

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

See:

4 Comments

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
&x as &str is 10 characters and x.as_str() is 10 characters. Same length.
If we're trying to go for the fewest characters, it's hard to do better than &*x.
11

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!"),
}

1 Comment

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

You can try:

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

3 Comments

It might improve the usefulness of your answer if you explain what &*stringthing means and does.
String implements Deref<Target = str>. So stringthing is dereferencend with *stringthing to a str and &*stringthing gets referenced to &str. According with the Rust documentation is this a more idiomatic way than using as_str().
This is good for whom has compulsion, s.as_ref() and s.as_str() are ugly, &*s is better.
1

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"),
    }
}

Comments

1

In Rust, you typically cannot use a String directly in a match statement because String is a dynamic, heap-allocated data type, and match expects values with a known and fixed set of possibilities at compile time.

However, you can use a String in a match statement by first converting it to a &str using the as_str() method or by using pattern matching with a reference to the String.

match expects exhaustive and known patterns: The match expression requires you to specify all possible patterns at compile time. String literals are known at compile time, so you can use them directly in a match. On the other hand, the content of a String is determined at runtime and can vary, so it cannot be directly used in a match.

Comments

0

As other answers already revealed, String is not str. So basically any function that can convert to an str will do. When reading something from the command line, I especially found useful the trim() method (get rid of the new line, and return an str. As marked in the comments, it does an automatic dereference during the call.

Here is the code I used:

let mut input: String = Default::default();
io::stdin().read_line(&mut input)
           .expect("Something bad happened");
match input.trim() {
    "a" => println!("0"),
    "b" => println!("1"),
    "c" => println!("2"),
    _ => println!("something else!"),
}

2 Comments

trim() does not "convert String to str", it operates on &str only. Auto-deref does the conversion, and trim() is an additional step you apply on top of it.
Hmm. Perhaps I was too happy after my 'Hello Word 2' application that I've found a new way to solve this. I'll incorporate the auto-deref part as soon as I understand it.
-2

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() {...}


2 Comments

This does not work. Error: expected tuple struct or tuple variant, found associated function String::from. play.rust-lang.org/…
my apologies. the example has been fixed.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.