Skip to main content

Ownership Model

TL;DR Every value has exactly one owner. Ownership transfers on move. The owner is responsible for dropping the value when it leaves scope — no GC, no manual free.

The Three Rules

  1. Every value has exactly one owner at any given time
  2. There can only be one owner at a time
  3. When the owner goes out of scope, the value is dropped
let s1 = String::from("hello");
let s2 = s1; // move: s1 is now invalid
// println!("{s1}"); // compile error: value borrowed after move
println!("{s2}"); // ok

Copy vs Move

Types that fit on the stack and are cheap to duplicate implement Copy. Assignment copies instead of moves.

let x: i32 = 5;
let y = x; // copy — both x and y are valid
println!("{x} {y}");

let s = String::from("hello");
let t = s; // move — s is invalidated
// println!("{s}"); // error

Copy types: all integer/float primitives, bool, char, (), tuples and arrays of Copy types.

!Copy types (move semantics): String, Vec<T>, Box<T>, anything that owns heap data.

Drop Order

Values are dropped in reverse declaration order. Inner scopes are dropped before outer scopes.

{
let a = String::from("a");
{
let b = String::from("b");
} // b dropped here
} // a dropped here

Struct fields drop in declaration order (top to bottom).

Ownership and Functions

Passing a value to a function moves it. The function becomes the new owner.

fn consume(s: String) {
println!("{s}");
} // s dropped here

let s = String::from("hello");
consume(s);
// s is invalid here — moved into the function

To use a value after passing it, either return it back, clone it, or pass a reference.

Gotchas

Partial moves invalidate the whole struct:

struct Pair { a: String, b: String }

let p = Pair { a: "hello".into(), b: "world".into() };
let a = p.a; // partial move
// println!("{}", p.b); // error: p is partially moved

Use ref bindings or restructure to avoid this.

Loop moves in closures:

let s = String::from("hello");
let f = || println!("{s}"); // s is captured by move if `move` is used
f();

Without move, closures capture by reference when possible.

Borrowing & ReferencesShared (&T) and exclusive (&mut T) borrows without transferring ownership LifetimesLifetime annotations and the relationship between reference validity and scope