Error while trying to borrow 2 fields from a struct wrapped in RefCell

You can manually invoke DerefMut and then save the resulting reference:

fn write(s: RefCell<S>) {
    let mut mut_s = s.borrow_mut();
    let mut tmp = &mut *mut_s; // Here
    let str = &tmp.data.string;
    tmp.writer.write(str.as_bytes());
}

Or in one line:

fn write(s: RefCell<S>) {
    let mut_s = &mut *s.borrow_mut(); // Here
    let str = &mut_s.data.string;
    mut_s.writer.write(str.as_bytes());
}

The problem is that borrow_mut doesn’t return your struct directly — it returns a RefMut. Normally, this is transparent as this struct implements Deref and DerefMut, so any methods called on it are passed to the underlying type. The pseudo-expanded code looks something like this:

use std::cell::RefMut;
use std::ops::{Deref, DerefMut};

fn write(s: RefCell<S>) {
    let mut mut_s: RefMut<S> = s.borrow_mut();
    let str = &Deref::deref(&mut_s).data.string;
    DerefMut::deref_mut(&mut mut_s).writer.write(str.as_bytes());
}

Rust doesn’t track field-level borrows across function calls (even for Deref::deref or DerefMut::deref_mut). This causes your error, as the deref_mut method would need to be called during the outstanding borrow from the previous Deref::deref.

The expanded version with the explicit borrow looks like this, with a single call to Deref::deref_mut:

use std::cell::RefMut;
use std::ops::DerefMut;

fn write(s: RefCell<S>) {
    let mut mut_s: RefMut<S> = s.borrow_mut();
    let tmp: &mut S = DerefMut::deref_mut(&mut mut_s);
    let str = &tmp.data.string;
    tmp.writer.write(str.as_bytes());
}

The compiler can then track that the two borrows from that temporary value are disjoint.


Note that this problem isn’t unique to RefCell! Any type that implements DerefMut can experience the same problem. Here’s some from the standard library:

Leave a Comment