Here's the line that breaks every newcomer's mental model — and once it clicks, Rust clicks.
Assignment can move
In most languages, let s2 = s1; either copies the value or makes both names point at the same object. Rust does neither for heap types. It moves: ownership of the heap buffer transfers from s1 to s2, and s1 becomes invalid. Touch s1 afterward and you get the famous error[E0382]: borrow of moved value.
Why move instead of copy?
If both s1 and s2 pointed at the same heap buffer and both tried to free it at scope end, you'd get a double free — a classic C crash. Rust prevents it structurally: after the move, only s2 owns the buffer, so only s2 frees it. There's no scenario where two owners fight over one allocation.
Stack types don't move — they copy
let y = x; where x is an i32 copies the value, because copying a stack scalar is trivial and safe — so x stays valid. The difference isn't arbitrary: types that are cheap and safe to duplicate copy; types that own heap resources move. The next lesson makes that split explicit.
If you really want two copies
You opt in with .clone() — an explicit, visible deep copy of the heap data. Rust never silently does the expensive thing; if a deep copy happens, you wrote the word clone.