Rust error E0382: borrow of moved value (use of moved value)
Fix Rust's E0382 borrow of moved value and use of moved value errors: why values move, the common causes, and the right fix for each.
E0382 means you used a variable after its value was moved somewhere else. A move transfers ownership, and the old variable can't be used afterwards. The two wordings are the same error:
- "borrow of moved value" when the later use only reads it (
println!,.len()), - "use of moved value" when the later use tries to move it again.
Cause 1: assignment moves
fn main() {
let name = String::from("Ferris");
let player = name;
println!("{name} joined as {player}");
}
error[E0382]: borrow of moved value: `name`
--> src/main.rs:4:16
|
2 | let name = String::from("Ferris");
| ---- move occurs because `name` has type `String`, which does not implement the `Copy` trait
3 | let player = name;
| ---- value moved here
4 | println!("{name} joined as {player}");
| ^^^^ value borrowed here after move
The message tells the whole story: the type isn't Copy, where it moved, and where you used it afterwards. Fix: borrow (let player = &name;) or clone (let player = name.clone();) if you truly need two owned copies.
Cause 2: a for loop over a collection
fn main() {
let tags = vec![String::from("rust"), String::from("arena")];
for t in tags {
println!("{t}");
}
println!("{} tags", tags.len());
}
error[E0382]: borrow of moved value: `tags`
for t in tags calls into_iter(), which consumes the vector. Loop over a reference instead: for t in &tags (each t is a &String).
Cause 3: moving inside a loop
fn archive(log: String) {
println!("archived {} bytes", log.len());
}
fn main() {
let log = String::from("boot ok");
for _ in 0..2 {
archive(log);
}
}
error[E0382]: use of moved value: `log`
rustc adds "value moved here, in previous iteration of loop". The first call took ownership, so there's nothing left to give the second time. Change the parameter to log: &str and call archive(&log). rustc even points at the parameter: "consider changing this parameter type in function archive to borrow instead if owning the value isn't necessary".
Cause 4: methods that take self
Some methods consume their receiver: into_iter(), into_bytes(), unwrap() on an Option<String>, a builder's build(self). After calling one, the variable is gone. Look for an as_ref(), iter() or &-taking alternative, or call it last.
Cause 5: closures with move
A move closure (common with thread::spawn) takes ownership of every variable it uses. Clone the value before the closure if you still need it afterwards: let name2 = name.clone(); then use name2 inside.
Choosing the fix
- Does the receiver only read the value? Borrow:
&value, and change the parameter to&str/&[T]/&T. Best in most cases. - Does it need to change it? Pass
&mut value. - Does it need to keep it (store in a struct, send to a thread)? Then it must own it. Clone if you also need it, or restructure so the move is the last use.
- Is the type small and plain? Derive
Clone, Copyfor it, and it will be copied instead of moved.
Example
fn archive(log: &str) {
println!("archived {} bytes", log.len());
}
fn main() {
let name = String::from("Ferris");
let player = &name; // borrow instead of move
println!("{name} joined as {player}");
let tags = vec![String::from("rust"), String::from("arena")];
for t in &tags {
println!("tag {t}");
}
println!("{} tags", tags.len());
let log = String::from("boot ok");
for _ in 0..2 {
archive(&log);
}
let backup = log.clone(); // two owners need two copies
let moved_log = log; // `log` is moved here, and not used afterwards
println!("{moved_log} / {backup}");
}
Output:
Ferris joined as Ferris
tag rust
tag arena
2 tags
archived 7 bytes
archived 7 bytes
boot ok / boot ok