Rust error E0507: cannot move out of borrowed content (behind a reference)
Fix Rust's E0507 cannot move out of index, behind a shared reference: borrow, clone, as_ref, take or mem::replace.
E0507 means you tried to move a value out of something you only borrowed. Older compilers said "cannot move out of borrowed content"; today's messages are more specific: "cannot move out of index of Vec<String>" or "cannot move out of self.name which is behind a shared reference".
Moving out would leave a hole: the owner (the vector, the struct) would still think it holds a valid String, and would drop it again later. So you can only look through a borrow, or replace what you take.
Case 1: taking an element out of a Vec by index
fn main() {
let names = vec![String::from("Ferris"), String::from("Corro")];
let first = names[0];
println!("{first}");
}
error[E0507]: cannot move out of index of `Vec<String>`
--> src/main.rs:3:17
|
3 | let first = names[0];
| ^^^^^^^^ move occurs because value has type `String`, which does not implement the `Copy` trait
|
help: consider borrowing here
|
3 | let first = &names[0];
| +
Fixes, depending on what you want:
- Just read it:
let first = &names[0]; - Your own copy:
let first = names[0].clone(); - Really take it out of the vector:
names.remove(0)(shifts the rest),names.swap_remove(0)(fast, changes order),names.pop(), orstd::mem::take(&mut names[0])(leaves an emptyStringbehind).
(With Vec<i32>, let x = v[0]; works fine: i32 is Copy, so it's copied rather than moved.)
Case 2: returning a field from a &self method
struct User {
name: String,
}
impl User {
fn name(&self) -> String {
self.name
}
}
fn main() {
let u = User { name: String::from("Ferris") };
println!("{}", u.name());
}
error[E0507]: cannot move out of `self.name` which is behind a shared reference
Usually the right getter returns a reference: fn name(&self) -> &str { &self.name }. Return self.name.clone() if the caller needs ownership, or write fn into_name(self) -> String to consume the whole struct.
Case 3: unwrap() on an Option field
self.result.unwrap() inside a &self method fails the same way, because unwrap takes the Option by value. rustc suggests the fixes:
self.result.as_ref().unwrap()orself.result.as_deref(): borrow the contents (Option<&String>/Option<&str>).self.result.take()in a&mut selfmethod: move the value out and leaveNonebehind.self.result.clone().unwrap()when you need an owned copy.
Case 4: dereferencing a reference into an owned value
let owned: String = *r; where r: &String tries to move the String out from behind r. Use r.clone(), or keep it as a reference.
The general toolbox
| You want to... | Use |
|---|---|
| look at it | &x, as_ref(), as_deref(), iter() |
| a copy | .clone() |
| take it, leave a default | std::mem::take(&mut x) |
| take it, leave something specific | std::mem::replace(&mut x, new) |
take it out of an Option |
opt.take() |
take it out of a Vec |
remove, swap_remove, pop, drain |
| consume the whole container | iterate with into_iter(), or a method taking self |
Example
struct Job {
name: String,
result: Option<String>,
}
impl Job {
fn name(&self) -> &str {
&self.name
}
fn peek(&self) -> Option<&str> {
self.result.as_deref()
}
fn take_result(&mut self) -> Option<String> {
self.result.take()
}
}
fn main() {
let mut names = vec![String::from("Ferris"), String::from("Corro"), String::from("Gopher")];
let first = &names[0];
println!("borrowed {first}");
let copy = names[1].clone();
let taken = std::mem::take(&mut names[2]);
println!("copy {copy}, taken {taken}, left behind {:?}", names[2]);
let removed = names.remove(0);
println!("removed {removed}, now {names:?}");
let mut job = Job { name: String::from("backup"), result: Some(String::from("ok: 42 files")) };
println!("{} peek {:?}", job.name(), job.peek());
let out = job.take_result();
println!("took {:?}, now {:?}", out, job.peek());
}
Output:
borrowed Ferris
copy Corro, taken Gopher, left behind ""
removed Ferris, now ["Corro", ""]
backup peek Some("ok: 42 files")
took Some("ok: 42 files"), now None