Skip to content
Select theme

What is the difference between String and &str?

Short answer: String owns the buffer its text sits in, and can grow it. &str is a read-only view of bytes that belong to something else — a String, a literal baked into the binary, or any other owner.

A String is a Vec<u8> with one promise attached: the bytes are valid UTF-8. The value itself is three machine words, 24 bytes on a 64-bit machine: a pointer, a length and a capacity. The text lives in a heap buffer those words point at, and owning that buffer is what lets it grow — push_str appends, and the buffer reallocates when it runs out of room.

str is the text itself, and it’s unsized, so a str never exists on its own. A &str is a borrow of one: a pointer and a length, two words, pointing at bytes owned elsewhere.

Literals have type &'static str, borrowed for the whole run of the program, because the text sits in the binary itself. Writing "hello" allocates nothing.

Build text with a String; read it through &str. A shared reference can’t change what it points at, so anything that appends or edits in place, like push_str and insert_str, needs the owned type.

Function parameters are where the split pays off. String implements Deref<Target = str>, so &some_string coerces to &str, and a parameter typed &str accepts both a literal and a borrow of a String with no clone at the call site. Taking String by value moves ownership in instead, and the caller is left without the text; why String isn’t Copy explains why there’s no free second copy. Copying a &str, by contrast, is harmless: a borrow owns nothing, and it’s two words.

A struct that stores text usually holds a String; one that views text someone else owns holds a &str. When a function you don’t control asks for a String, String::from("text") makes the owned copy; the next article in this chapter compares those spellings.