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'