Start with the idea
String owns a growable UTF-8 buffer and &str borrows one. Because a character can be several bytes, s[0] is not allowed at all: you choose .bytes(), .chars(), or a byte range you know lands on a boundary. That refusal is the point — it makes an entire class of encoding bug impossible.
UTF-8 stores text as bytes, and a visible character may require more than one byte. In café, len() is five bytes, while chars().count() yields four Unicode scalar values. Neither number necessarily counts what a person sees as a grapheme: a letter plus a combining accent can be two scalar values displayed as one. Rust deliberately makes the unit explicit, so you cannot assume that the fifth byte begins a character.
A String owns and can grow its buffer. A &str borrows a valid slice of UTF-8 text, whether the source is a string literal or part of a String.
Keep learning, for free
The rest of this lesson is waiting for you.
Create a free account to read the complete explanation, see the infographic, explore the code, and try the exercises. All 742 lessons and algorithm steps are included.
No payment details. Your account opens the complete Academy.