Reputation: 16805
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 String
s in Rust?
Upvotes: 448
Views: 214350
Reputation: 1046
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!"),
}
Upvotes: 0
Reputation: 4993
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.
Upvotes: 1
Reputation: 13
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() {...}
Upvotes: -2
Reputation: 4533
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.
Upvotes: 433
Reputation: 51
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"),
}
}
Upvotes: 1
Reputation: 1996
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!"),
}
Upvotes: 198
Reputation: 89
You can try:
fn main() {
let stringthing = String::from("c");
match &*stringthing {
"a" => println!("0"),
"b" => println!("1"),
"c" => println!("2"),
_ => println!("else")
}
}
Upvotes: 3
Reputation: 16630
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!"),
}
Upvotes: 11
Reputation: 1874
You could also do
match &stringthing as &str {
"a" => println!("0"),
"b" => println!("1"),
"c" => println!("2"),
_ => println!("something else!"),
}
See:
Upvotes: 26