lotsoftools

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.

Recommended Reading