String vs &str in Rust
Both contain utf-8 encoded text, but:
String
owns the data stored within it. When theString
is deallocated the text data it stores is deallocated as well.&str
borrows data that is stored elsewhere (usually in aString
), it doesn't store any text data of its own. When a&str
is deallocated the data it points to is left untouched.
Handily, a &str
can be shorter than the String
it references. This helps make string handling fast and memory efficient as we can simply break up a pre-existing String
into chunks that all just reference the original String
, no heap allocations or data copying needed.
In the example below, text data is only allocated once when we read the file into memory. The rest of the strings are all just references to the original.
use std::fs::read_to_string;
fn main() {
// Reads text from a file and stores it in memory in a String
let input: String = read_to_string("src/example.txt").unwrap();
// Remove leading and trailing whitespace. No memory is copied on this line,
// `trimmed` just points to the parts of `input` that don't include leading
// or trailing whitespace.
let trimmed: &str = input.trim();
// No text data gets copied here either.
// Each `&str` representing a line of text simply points to data already
// stored in `input` above.
for line in trimmed.lines() {
println!("{}", line);
}
}
String literals
String literals in Rust are &str
s.
When Rust compiles your code the text gets stored in the (read-only) data segment of the generated program, and the &str
references that data. Because string literals live for the entire duration of the program they have a static lifetime, so the full type can be written as &'static str
.
let string: &'static str = "Hello world";
Check out the Rust docs for more details on lifetimes and &str.