Functions take ownership too
Worked examples
Read the claim, then run it and check the machine agrees. One at a time — nothing here is taken on trust.
fn describe(v: Vec<i32>) -> String {
format!("{} items", v.len())
}
fn main() {
let data = vec![10, 20, 30];
let msg = describe(data); // data MOVED into describe
// println!("{data:?}"); // <- E0382: value borrowed after move
// // (describe owns it now, then frees it)
println!("{msg}");
}
Passing data to describe moves it — the commented line is E0382,
the same diagnosis as let s2 = s1, just at a call site. When
describe returns, its parameter v goes out of scope and the Vec
is freed. The caller kept only what describe returned (a
String). Prints 3 items.
fn measure(v: Vec<i32>) -> (Vec<i32>, i32) {
let sum: i32 = v.iter().sum(); // .iter() borrows, doesn't move
(v, sum) // hand v back alongside the answer
}
fn main() {
let data = vec![1, 2, 3, 4];
let (data, total) = measure(data); // rebind the returned owner
// data is ours again because measure RETURNED it:
println!("sum {total}, and still have {} items", data.len());
}
measure takes ownership, computes the sum (.iter() only
borrows internally), and returns the Vec with the answer. The
caller rebinds data to the returned owner and carries on. It
works — and you can feel the tax: a function that only wanted to add
up numbers made you catch a tuple. Prints sum 10, and still have 4
items.
fn grow(mut v: Vec<i32>, x: i32) -> Vec<i32> {
v.push(x); // mutate the value we own
v // move it back out
}
fn main() {
// each call takes ownership and returns it, so the next call can take it:
let v = grow(grow(grow(Vec::new(), 1), 2), 3);
println!("{v:?}"); // [1, 2, 3]
// the same handle, threaded through three owners in turn:
let same = grow(v, 4);
println!("{same:?}");
}
grow owns the Vec (note mut v — a by-value parameter can be made
mutable), pushes, and returns it, so the result feeds straight into
the next grow. Threading works and composes, but every function in
the chain has to give the Vec back explicitly. Borrowing (m03) lets
each step take &mut v and skip the hand-back entirely. Prints
[1, 2, 3] then [1, 2, 3, 4].
Check the concept
One question at a time. Unsure? Revisit the lecture, then answer.
The challenge
Pass the quiz to unlock the challenge — your code will still be waiting here.