Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Difference between borrow_mut on a RefCell<X> and RefCell<&X>

If I get correctly it is not possible to create a mutable borrow over a std::rc::Rc in Rust, you have to use Cell or RefCell. But anyway I cannot understand how to use them. For example consider this simple example:

use std::cell::RefCell;

struct X (i32);

impl X {
    fn foo(&mut self) {
        self.0 = 0;
    }
}

fn main () {
    let x = X(5);
    let rcx = RefCell::new(&x);

    let mut mutx: std::cell::RefMut<&X> = rcx.borrow_mut();
    (*mutx).foo();
}

I get the following error:

16:5: 16:9 error: cannot borrow immutable local variable `mutx` as mutable
16     mutx.foo();

But if I remove the reference from line (and update type of mutx):

let rcx = RefCell::new(x);

Everything is fine. But I cannot understand why, since RefMut::deref_mut() -> &mut T the deference called at line 16 should return &&mut T in the first case, while &mut T in the second case. But since the compiler should apply many * as needed (If I get how deref coercion works) there should be no difference between RefMut<X>::deref_mut() and RefMut<&X>::deref_mut()

Edit: By mistake I forgot to write mut at line 15 as in the linked example is correctly is written. So now it's let mut mutx...

like image 683
Kill KRT Avatar asked Sep 27 '22 17:09

Kill KRT


1 Answers

The problem stems from the fact that you've stored an immutable reference in the RefCell. I'm unclear why you would want such a thing. The normal pattern is to put the entire value into the RefCell, not just a reference:

fn main () {
    let rcx = RefCell::new(X(5));

    let mut mutx = rcx.borrow_mut();
    mutx.foo();
}

Problem from original question

You have two compounding errors. Let's check the entire error message:

<anon>:16:5: 16:12 error: cannot borrow immutable borrowed content as mutable
<anon>:16     (*mutx).foo();
              ^~~~~~~
<anon>:16:7: 16:11 error: cannot borrow immutable local variable `mutx` as mutable
<anon>:16     (*mutx).foo();
                ^~~~

Note the second error — "cannot borrow immutable local variable mutx". That's because you need to declare the mutx variable mutable:

let mut mutx: std::cell::RefMut<&X> = rcx.borrow_mut();

That will allow mutx to participate in DerefMut.

like image 166
Shepmaster Avatar answered Dec 16 '22 13:12

Shepmaster