Understanding and Solving Rust Error E0507
Rust Error E0507: A borrowed value was moved out
Rust error E0507 occurs when there is an attempt to move out a borrowed value, which is not allowed in the Rust ownership system. Let's examine this error with an erroneous code example:
use std::cell::RefCell;
struct TheDarkKnight;
impl TheDarkKnight {
fn nothing_is_true(self) {}
}
fn main() {
let x = RefCell::new(TheDarkKnight);
x.borrow().nothing_is_true(); // error: cannot move out of borrowed content
}
In the above code, the nothing_is_true method takes ownership of self. However, self cannot be moved because .borrow() only provides a reference to the content owned by the RefCell. There are three possible solutions to fix this error:
1. Avoid moving the variable
One option to fix the error is to avoid moving the variable. You can achieve this by changing the method to take a reference instead of ownership. The modified code would look like this:
use std::cell::RefCell;
struct TheDarkKnight;
impl TheDarkKnight {
fn nothing_is_true(&self) {}
}
fn main() {
let x = RefCell::new(TheDarkKnight);
x.borrow().nothing_is_true(); // ok!
}
2. Reclaim the ownership
Another method to fix the error is to reclaim the ownership of the variable. Use the .into_inner() method to achieve this. Here's the updated code:
use std::cell::RefCell;
struct TheDarkKnight;
impl TheDarkKnight {
fn nothing_is_true(self) {}
}
fn main() {
let x = RefCell::new(TheDarkKnight);
let x = x.into_inner(); // we get back ownership
x.nothing_is_true(); // ok!
}
3. Implement the Copy trait
Implement the Copy trait on the type to create a copy of the value before passing it to the method. Make sure to also derive the Clone trait when doing this. The updated code will look like this:
use std::cell::RefCell;
#[derive(Clone, Copy)] // we implement the Copy trait
struct TheDarkKnight;
impl TheDarkKnight {
fn nothing_is_true(self) {}
}
fn main() {
let x = RefCell::new(TheDarkKnight);
x.borrow().nothing_is_true(); // ok!
}
Error E0507 with mutable borrowed structs
Moving a member out of a mutably borrowed struct will also cause E0507 error:
struct TheDarkKnight;
impl TheDarkKnight {
fn nothing_is_true(self) {}
}
struct Batcave {
knight: TheDarkKnight
}
fn main() {
let mut cave = Batcave {
knight: TheDarkKnight
};
let borrowed = &mut cave;
borrowed.knight.nothing_is_true(); // E0507
}
To fix this error, put something back using mem::replace. Here's the updated code:
struct TheDarkKnight;
impl TheDarkKnight { fn nothing_is_true(self) {} }
struct Batcave { knight: TheDarkKnight }
use std::mem;
let mut cave = Batcave {
knight: TheDarkKnight
};
let borrowed = &mut cave;
mem::replace(&mut borrowed.knight, TheDarkKnight).nothing_is_true(); // ok!
For more information on Rust's ownership system, refer to the References & Borrowing section of the Rust Book.