Skip to content
Select theme

What happens when you assign one struct to another variable?

Short answer: let backup = person; moves the whole struct into backup — every field at once, Copy fields included — and person is invalidated. The assignment copies instead of moving only when the struct’s type implements Copy, which for a struct you wrote means deriving it, over fields that are all Copy themselves.

The previous step, how ownership works with structs, ended on this line: use the struct as one value and every field goes with it. Assignment is that move. Every block on this page is a complete src/main.rs; start from any Cargo project (cargo new struct-assign will do — the output doesn’t depend on the name) and replace the file one block at a time:

backup: Ada is 36

age is a u32, a Copy type, and it moved too. The unit of the move is the struct, so the whole binding is invalidated, not field by field. Read person after the assignment and the compiler answers with the same E0382 you get from passing the struct to a function:

error[E0382]: borrow of moved value: `person`
--> src/main.rs:15:36
|
7 | let person = Person {
| ------ move occurs because `person` has type `Person`, which does not implement the `Copy` trait
...
12 | let backup = person;
| ------ value moved here
...
15 | println!("person is gone: {}", person.age);
| ^^^^^^^^^^ value borrowed here after move
|
note: if `Person` implemented `Clone`, you could clone the value
--> src/main.rs:1:1
|
1 | struct Person {
| ^^^^^^^^^^^^^ consider implementing `Clone` for this type
...
12 | let backup = person;
| ------ you could clone this value
For more information about this error, try `rustc --explain E0382`.

The old binding isn’t cleared; it’s marked uninitialised, which is what happens to the original variable after a move in full. Re-initialising it (person = Person { … }) is the way back to work.

A struct whose type implements Copy is duplicated by the assignment, and both bindings stay usable:

a is still here: 1 2
b: 1 2

Two conditions, and both have to hold. Every field has to be Copy — one String field and the struct moves again — and the derive has to be written, because your own structs are never Copy until you ask for it. How to tell whether a type will move or copy has the test, and what blocks the derive.

The other shape of struct assignment writes to a field, and that moves one field, not the struct:

target is whole: Ada is 45
source.age still works: 36

target never lost a field, so it stays usable as one value; the old name was dropped by the assignment and the new one put in its place. source is the one that changed — its name left, which leaves the struct partially moved, and what is a partial move? covers what that does to the rest of it.

Assignment gives the struct away. When the copy is the point — a snapshot to fall back on — clone it:

person: Ada is 36
backup: Ada is 36

#[derive(Clone)] is what makes person.clone() exist. When should you clone? is about when that’s the right answer, and how to fix error E0382 collects every fix for the error above.