Recipe
Predict what happens to a value at each use
Use when: you're reading a short program and need to say whether it compiles, which names can still be used at a line, or where a value is dropped
Goal: for every use of every value: read, moved, copied, cloned or dropped, and the line of any E0382
Taught in Predicting moves · extends Find the line that frees each value
Quick recipe
-
1
For each
letand each function parameter, write down the variable, its type, and the}that ends its scope.Example
In
fn main() { let a = String::from("x"); let n = 3; let b = a; println!("{b} {n}"); }:a: String,n: i32andb: String, all ending atmain's}.Why: an owner that still owns its value at that brace drops it there (rule 3).
-
2
Mark each variable's type as Copy (numbers,
bool,char, tuples and arrays of those) or not (String,Vec, anything containing one).Example
n: i32is Copy, so it is usable everywhere up to}.aandbareStrings, so they need tracking.- Copy — every use duplicates it; it can never be moved, so it stays usable to the end of its scope.
- not Copy — track it through the next steps.
Why: a Copy value has nothing to free, so duplicating it is always safe.
-
3
Go top to bottom and label each use of a tracked name. A read (
println!,.len(), indexing) leaves ownership where it is. A move hands ownership on and makes the name moved from:let x = name;, passing it to a parameter of an owned type, putting it in a tuple, or returning it. A clone (name.clone()) leaves the name as owner and makes a new value. Taking one non-Copy part of a tuple is a partial move of that part only.Example
let b = a;is a move: from here,ais moved from andbowns theString.println!("{b} {n}")is a read ofband a read ofn.Why: these are the only ways ownership can change hands.
-
4
If a move is inside a loop, it repeats on every pass. If a move is inside one branch of an
if, treat the value as possibly moved after theif. If a moved-frommutvariable is assigned a new value, it owns again from that line.- a move in a loop body of a variable declared outside the loop — E0382 on that move, on the second pass.
- a move in an
ifbranch, then a use after theif— E0382 on the later use.
Why: the compiler checks every path without running the program, so the worst path decides.
-
5
Any use of a name while it is moved from is E0382, reported at that use. Otherwise the program compiles, and each value is dropped at the closing brace of whichever variable owns it last.
Example
Nothing uses
aafterlet b = a;, so the example compiles. At},bdrops theString;ahas nothing to drop;nfrees nothing.- a late use only reads — "borrow of moved value".
- a late use tries to move again — "use of moved value".
Why: a moved-from name holds no value; reading it would read a buffer another owner controls.
Common mistakes
- Thinking
println!or.len()moves a value. They only read it. - Thinking a clone earlier in the program protects a later plain move. Each
let x = name;is judged on its own. - Forgetting that a loop body runs more than once.
- Thinking a moved-from variable is dropped at its brace. It has nothing to drop.
- Thinking a
Stringshort enough, or a tuple that is mostly numbers, might be Copy.