Rust runtime mutable reference rules with RefCell

Viewed 44

THE QUESTION

When are RefCell counted down?

THE CASE

// Working
use std::cell::RefCell;

fn main() {
    let username = RefCell::new("");
    *username.borrow_mut() = "Genese";
    *username.borrow_mut() = "Salathiel";
    println!("{}", username.borrow()); // Salatthiel
}

Then...

// !working
use std::cell::RefCell;

fn main() {
    let username = RefCell::new("");
    let mut username_mutable_borrow = username.borrow_mut();
    *username_mutable_borrow = "Genese";
    let mut username_mutable_borrow = username.borrow_mut();
    *username_mutable_borrow = "Salathiel";
    println!("{}", username.borrow());
}

// thread 'main' panicked at 'already borrowed: BorrowMutError', src/main.rs:7:48

I did other experiments with std::ops::Deref without much success or insights.

1 Answers

RefCell::borrow_mut() returns a RefMut. If this RefMut is stored in a variable, it lives til the end of the containing scope. This is the reason for the panic in your second example - both username_mutable_borrows live until the end of the scope, so they're colliding.

However, in the first example, you don't store the RefMuts in variables. They are temporaries. The scope of temporaries is the smallest scope of the following:

  • The entire function body.
  • A statement.
  • The body of a if, while or loop expression.
  • The else block of an if expression.
  • The condition expression of an if or while expression, or a match guard.
  • The expression for a match arm.
  • The second operand of a lazy boolean expression.

The smallest applicable scope here is the containing statement, and so they live only until the end of it. Therefore they do not collide.

Related