Ownership

Ownership Transfer Between Variables

When a non-Copy value is assigned from one variable to another (let dest = src; or dest = src;), ownership transfers from src to dest. Only dest remains responsible for dropping the resource when it goes out of scope.

Sequential Ownership Chains

Ownership can move through a chain of variables across nested blocks. At any instant, only the final variable in the chain is initialized and active:

fn main() {
    let first = String::from("chained resource");

    // 1. Move from `first` to `second`:
    let second = first;

    let fourth = {
        // 2. Move from `second` into inner variable `third`:
        let third = second;
        // 3. Move out of the block via tail expression into `fourth`:
        third
    };

    println!("Active owner is fourth: '{fourth}'");
}
Active owner is fourth: 'chained resource'
first (moved) ──> second (moved) ──> third (moved) ──> fourth (sole active owner -> dropped at `}`)

Reassignment Drops the Previous Value Before Taking Ownership

When you transfer ownership into a mutable variable that already owns a value (dest = src;), Rust first drops dest's existing value so its old memory is not leaked, and then moves src into dest:

struct Tracked(&'static str);

impl Drop for Tracked {
    fn drop(&mut self) {
        println!("  [Drop] {}", self.0);
    }
}

fn main() {
    let mut slot = Tracked("original value in slot");
    let replacement = Tracked("replacement value");

    println!("Before `slot = replacement;`");
    slot = replacement; // 1. Drops "original value in slot", 2. Moves `replacement` into `slot`
    println!("After `slot = replacement;`, slot holds: {}", slot.0);
}
Before `slot = replacement;`
  [Drop] original value in slot
After `slot = replacement;`, slot holds: replacement value
  [Drop] replacement value

Swapping Ownership Between Two Variables (std::mem::swap)

Because moving let temp = a; a = b; b = temp; requires a and b to be local variables, Rust provides std::mem::swap(&mut a, &mut b) to exchange ownership between any two mutable places (including array elements or struct fields) without deallocating or cloning:

fn main() {
    let mut left = String::from("left");
    let mut right = String::from("right");

    std::mem::swap(&mut left, &mut right);
    println!("left = '{left}', right = '{right}'");
}
left = 'right', right = 'left'