🎓 A1Learner
🔍

Rust Partial Moves

A partial move takes one part of a value out and leaves the rest in place. The whole value then stops being usable.

Move one field out

person is a Person with name "Alice" and city "Paris" — the struct is defined in the full example below. One line moves the name out, and the city stays in place:

let n = person.name;
println!("moved name: {n}");
println!("city stayed: {}", person.city);

The whole value is off limits

After that move, the whole person can no longer be used — Rust knows one part of it is gone:

println!("{person:?}");
// error E0382: borrow of partially moved value: `person`

A Copy field just copies

A field whose type is Copy is never really moved out. Binding it copies the value, so the field stays usable afterwards:

struct Tag { id: u8, label: String }
let tag = Tag { id: 7, label: String::from("new") };
let Tag { id, label } = tag;
println!("id {id}, label {label}");
println!("tag.id still works: {}", tag.id);

A type with Drop cannot be partly moved

If a type implements Drop, its drop code needs the whole value at the end. Rust refuses to let a piece out of it (guard here is a Guard value, and Guard implements Drop):

let Guard { name } = guard;
// error E0509: cannot move out of type `Guard`, which implements the `Drop` trait

Example

#[derive(Debug)]
struct Person {
    name: String,
    city: String,
}
fn main() {
    let person = Person { name: String::from("Alice"), city: String::from("Paris") };
    let Person { name, ref city } = person;
    println!("name = {}", name);
    println!("city = {}", city);
    println!("city from person = {}", person.city);
}

Key points

  • A partial move takes one part of a value, like one field, and leaves the other parts behind

In this example, one let line splits person two ways. The pattern binds name with no ref, so the String moves out of person and into name. It binds city with ref, so city is only a &String borrowing the field. The first two lines print the moved name and the borrowed city. The last line proves the point of a partial move: person.city still works, because that part never moved. Printing the whole person would fail with E0382 — one part of it is gone.

Note

Many languages have no middle state between "whole value usable" and "whole value gone".

Rust tracks ownership field by field.

The parts that stayed valid stay available.

Only the moved part is switched off.

Try it Yourself

Edit the code, then press Run.

Running is simulated · Rust Playground

Exercise

After let Person { name, ref city } = person;, which of these still works?