What is the difference between String and &str in Rust?
Learn the difference between String and &str in Rust — owned heap text versus borrowed slices, deref coercion, and why APIs take &str. With examples.
Expected Interview Answer
String is a growable, heap-allocated, owned UTF-8 string that you can mutate, while &str is an immutable borrowed view (a slice) into UTF-8 text that someone else owns.
A String owns its buffer and is responsible for freeing it, so it carries a pointer, length, and capacity and can grow or shrink. A &str is a fat pointer (pointer plus length) that borrows existing bytes — it might point into a String, into a string literal baked into the binary with a 'static lifetime, or into any other UTF-8 buffer. Because a &String coerces to &str automatically via deref, idiomatic APIs accept &str parameters so they work with both owned and borrowed data.
- String gives ownership and mutability when you need to build or modify text
- &str is cheap to pass — no allocation or copying, just a borrow
- Accepting &str makes functions accept both literals and owned Strings
- Slicing lets you reference part of a string without copying it
- Both guarantee valid UTF-8 at the type level
AI Mentor Explanation
A String is like owning the actual physical scorebook for a match — you can write new deliveries into it, erase, and add pages because it is yours. A &str is like a photographer pointing a lens at one page: they can read the runs and wickets shown but cannot alter anything, and their view is valid only while the real scorebook stays open in your hands.
Step-by-Step Explanation
Step 1
Recognize ownership
String owns a heap buffer with pointer, length, and capacity; &str only borrows bytes it does not own.
Step 2
Create a String
Use String::from("hi"), "hi".to_string(), or String::new() then push characters to build growable text.
Step 3
Borrow as &str
Pass &my_string; deref coercion turns &String into &str so the function borrows without copying.
Step 4
Prefer &str in signatures
Accept &str parameters so callers can pass literals, slices, or owned Strings interchangeably.
Step 5
Convert when needed
Call .to_owned() or .to_string() on a &str to get an owned String you can mutate and store.
What Interviewer Expects
- Clear distinction between owned and borrowed data
- Understanding that &str is a slice (fat pointer with length)
- Knowledge of deref coercion from &String to &str
- Awareness that string literals are &'static str
- Why idiomatic APIs take &str instead of &String
Common Mistakes
- Claiming &str is always a substring of a String only
- Taking &String parameters instead of &str
- Forgetting that a String owns and frees its heap buffer
- Thinking conversion between them is always free
- Confusing capacity with length on a String
Best Answer (HR Friendly)
“A String is text your program owns and can change, like your own editable notebook, while &str is just a borrowed peek at some text you cannot alter. Rust functions usually accept the borrowed &str form so they work with any kind of text without copying it.”
Code Example
fn greet(name: &str) {
println!("Hello, {name}!");
}
fn main() {
let literal: &str = "Ada"; // &'static str
let mut owned: String = String::from("Grace");
owned.push_str(" Hopper"); // mutate the owned buffer
greet(literal); // pass a &str
greet(&owned); // &String coerces to &str
let slice: &str = &owned[0..5]; // borrow part of the String
println!("{slice}");
}Follow-up Questions
- Why do string literals have a 'static lifetime?
- How does deref coercion turn &String into &str?
- When would you accept String by value instead of &str?
- What does slicing a String on a non-char boundary do?
- How is a &str represented in memory?
MCQ Practice
1. Which statement about &str is correct?
&str is a fat pointer (pointer + length) borrowing UTF-8 bytes it does not own; it is immutable and can point into a String, a literal, or any buffer.
2. What is the idiomatic parameter type for a function that only reads text?
Accepting &str lets callers pass literals, slices, and owned Strings (via deref coercion) without forcing an allocation.
3. How do you get an owned String from a &str?
Both .to_owned() and .to_string() allocate a new heap buffer and copy the bytes to produce an owned String.
Flash Cards
What does String own? — A growable heap-allocated UTF-8 buffer with a pointer, length, and capacity; it frees the buffer when dropped.
What is a &str? — An immutable borrowed slice of UTF-8 text: a fat pointer (pointer + length) into a buffer owned elsewhere.
Why take &str, not &String? — &str accepts literals, slices, and owned Strings via deref coercion, so the API is more flexible.
Type of a string literal? — &'static str — it lives in the binary for the whole program's lifetime.
How to make a &str owned? — Call .to_string() or .to_owned() to allocate and copy into a new String.