Why Rust Doesn't Let You Simply Compare String with "hello"?
\n\nIf you're just starting to learn Rust and have already encountered the need to match a variable of type String with some string literal like "hello" or "world", you've probably seen a strange compiler error. You write something like:
let user_input = String::from("start");\nmatch user_input {\n "start" => println!("Starting!"),\n "stop" => println!("Stopping!"),\n _ => println!("Unknown command"),\n}\n\n\nAnd the compiler outputs something like: "expected struct `String`, found `&str`". Sound familiar?
\n\nOn Stack Overflow, the question "How to match a String against string literals?" has thousands of views — it's a real pain point for beginners. In this article, we'll break down why this happens and show three simple ways to solve the problem. You'll learn how Rust's ownership and borrowing system works in practice and stop being afraid of compiler errors.
\n\nThe Nature of the Conflict: String vs &str
\n\nTo understand the problem, you need to recall the basics. Rust has two main types for working with text:
\n\n- \n
String— an owned string stored on the heap. It can be modified, grow, and shrink. Example:let s = String::from("hello");\n &str— a string slice. It is a reference to part of a string (or to a string literal stored directly in the program's binary). Example:"hello"is exactly&'static str. \n
When you write match user_input { "start" => ... }, you are trying to compare a String with a &str. The compiler says: "I don't know how to match them directly; the types are different!". And this is good — Rust protects you from implicit conversions that could lead to performance loss or hidden bugs.
But what to do then? There are three simple and elegant solutions.
\n\nSolution 1: Borrowing via as_str()
\n\nThe most direct and understandable way is to get a string slice (&str) from a String using the as_str() method. This method returns a reference to the string's content without copying it. It looks like this:
fn main() {\n let command = String::from("start");\n\n match command.as_str() {\n "start" => println!("System starting..."),\n "stop" => println!("Stopping..."),\n "pause" => println!("Pausing..."),\n _ => println!("Unknown command: {}", command),\n }\n}\n\n\nWhy does this work? as_str() returns a &str, which can now be compared with literals. Rust sees that both operands are &str, and pattern matching works perfectly.
Pros: simplicity, readability, zero overhead (borrowing, not copying).
\n\nCons: you need to remember to call the method. But that's a minor detail.
\n\nSolution 2: Comparison in an if Condition
\n\nIf you don't need the full power of match, you can use regular if with the eq() method or the == operator. Rust can compare String and &str via the PartialEq trait, which is implemented for this pair of types.
fn main() {\n let user_input = String::from("admin");\n\n if user_input == "admin" {\n println!("Access granted!");\n } else if user_input == "guest" {\n println!("Guest access");\n } else {\n println!("Invalid login");\n }\n}\n\n\nThis works because the compiler automatically coerces String to &str during comparison. But in match, such coercion does not exist — it requires an exact