Skip to content
Select theme

Why does Rust move values instead of copying them?

Short answer: assigning a String does not copy its data, it transfers ownership. Rust refuses to leave two variables pointing at the same heap buffer, because freeing it twice would be a memory bug. The variable you assigned from is not pointing at anything any more — so the compiler stops you from using it.

At first glance this looks like a bug. Both lines print a string — why is one of them illegal?

A String is three words on the stack: a pointer to a heap buffer, a length, and a capacity. The text itself lives on the heap.

flowchart LR
  A["s1 — owns the heap buffer"] -->|"let s2 = s1"| B["s2 — now owns the heap buffer"]
  A -.-> C["s1 — moved out, unusable"]

If Rust copied the three stack words the way a language with a garbage collector might, s1 and s2 would both believe they own the same heap buffer. When both go out of scope, the buffer is freed twice. That is a double free — and in C it is exactly the kind of bug Rust exists to make impossible.

So the compiler makes a choice: it moves the value. Ownership transfers to s2, and s1 becomes invalid. Using it afterwards is the E0382 error above.

Not everything moves. Simple values that live entirely on the stack implement the Copy trait, and assignment copies them:

i32, f64, bool, char, and references are all Copy. Tuples and arrays of Copy types are Copy too, so (1, 2) is copied while (String, i32) is moved.

The rule of thumb: if the type manages something on the heap, or implements Drop to clean up after itself, it does not implement Copy.

How to keep using a value after passing it on

Section titled “How to keep using a value after passing it on”

Three options, in order of preference:

If the function only needs to read the value, pass a reference and nothing moves:

If you genuinely need two independent values, say so explicitly:

clone() is honest but not free — it allocates and copies. Reaching for it whenever the borrow checker complains is the most common way to write slow Rust. Try borrowing first.

A function that takes ownership can return it: