6

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...

Peter Hall
  • 53,120
  • 14
  • 139
  • 204
Kill KRT
  • 1,101
  • 2
  • 17
  • 37

1 Answers1

4

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.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
  • Sorry I put the `mut` in the linked code and I didn't update the code in the post. Anyway (regarding the first issue), also if I use `RefCell::new(x)` (without reference) I am storing a immutable value in `RefCell`, but this don't generate any error. The reason why I'm using a reference here is that my original code is actually a little more complicated (you can check here: http://is.gd/XoROad) – Kill KRT Sep 15 '15 at 18:11
  • 1
    *`RefCell::new(x)` [is] storing a immutable value* — this is a common misconception, but it is **not** an immutable value. You might have an immutable *binding* to the value, but when you transfer ownership, you can [pick what mutability you have](http://is.gd/di1UDT). – Shepmaster Sep 15 '15 at 18:14
  • 2
    @KillKRT Although Shepmaster is correct, it could be more clear. What you need to understand is that values have a fixed location (on the stack, heap or whatever). Those can be immutable. However, when you move from one value to another `foo = bar`, ownership of the contained memory is transferred. This transfer can be to a mutable location, which can then give transitive mutable access to the contents. But you can't do this with references because you can't move out of references, so you can never move the referenced data to a mutable location. – Veedrac Sep 15 '15 at 21:41
  • 2
    @KillKRT `RefCell` is also a bit special, because it allows breaking the transitivity of mutability: an immutable `RefCell` can give you mutable access to its contents. If its contents is a value, it can give `&mut T`. If its contents, though, is a reference, it can only give you an `&mut &T`, which lets you modify where the inner reference points to but not the value pointed to by the inner reference. – Veedrac Sep 15 '15 at 21:46
  • @Veedrac thank you for your clarification, it helped me a lot. – Kill KRT Sep 16 '15 at 11:00