399

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?

vallentin
  • 23,478
  • 6
  • 59
  • 81
Jeroen
  • 15,257
  • 12
  • 59
  • 102
  • 6
    `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 Jan 10 '20 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! – Jeroen Jan 10 '20 at 21:04

8 Answers8

361

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.

mcherm
  • 23,999
  • 10
  • 44
  • 50
Tijs Maas
  • 3,793
  • 2
  • 16
  • 7
  • 4
    using rust 1.4.0 one can use the `trim()` function. Just using `as_ref()` doesn't match the string. – futtetennista Dec 01 '15 at 20:17
  • 1
    I think the match fails because of whitespace that `trim()` removes. This is nice for deferencing to match against user input. – Gerard Sexton Sep 20 '16 at 13:25
  • 2
    It doesn't work. It can only match _ if I get String from read_line. – Masked Man Nov 26 '16 at 10:20
  • Don't know much about how rust manages different types of strings, but [it seems to work on a basic example](https://play.rust-lang.org/?gist=d3a1379484fd4a01aa1c16e6cb32d187&version=nightly). – tforgione Jan 24 '18 at 09:40
  • 2
    @MaskedMan `read_line` reads a line. Lines end in `\n`. `.trim_end()` (or, more precisely, `trim_end_matches('\n')`) will remove that for you. – wizzwizz4 Jun 17 '21 at 17:35
  • I'm not getting `.as_str()` at all. It is not being allowed for a string parameter, "`xx`": "`foo( xx : &str )`". While ... "`match xx { "ABC" => "XYZ", ... }`", works fine. Which is a '[borowed](https://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html) instance/parameter. How does that work-in if the correct, or _better_, method is to use `as_str()`? – will Nov 13 '21 at 16:04
189

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!"),
}
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Anonymous Coward
  • 1,906
  • 1
  • 10
  • 2
24

You could also do

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

See:

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Marco Scannadinari
  • 1,774
  • 2
  • 15
  • 24
10

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!"),
}
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
A.B.
  • 15,364
  • 3
  • 61
  • 64
3

You can try:

fn main() {
    let stringthing = String::from("c");
    match &*stringthing {
        "a" => println!("0"),
        "b" => println!("1"),
        "c" => println!("2"),
        _ => println!("else")
    }
}
omrihhh
  • 79
  • 4
  • 11
    It might improve the usefulness of your answer if you explain what `&*stringthing` means and does. – Seth Difley May 03 '20 at 15:53
  • `String` implements `Deref`. 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()`. – Kaplan Aug 19 '22 at 06:26
  • This is good for whom has compulsion, `s.as_ref()` and `s.as_str()` are ugly, `&*s` is better. – Sunding Wei Sep 02 '23 at 08:53
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"),
    }
}
u_mulder
  • 54,101
  • 5
  • 48
  • 64
1

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


  • 1
    This does not work. Error: expected tuple struct or tuple variant, found associated function `String::from`. https://play.rust-lang.org/?version=stable&mode=debug&edition=2021 – FreelanceConsultant May 16 '23 at 13:30
1

You can convert the String to a &str using the as_str() method, and then match on the &str value like so:

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

Or you can bind the String value to a variable, and then match on the variable like so:

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

Or you can use the == operator to compare the String value with a string literal like so:

fn main() {
    let stringthing = String::from("c");
    if stringthing == "a" {
        println!("0");
    } else if stringthing == "b" {
        println!("1");
    } else if stringthing == "c" {
        println!("2");
    } else {
        println!("other");
    }
}
AlexaP
  • 179
  • 2
  • 1