Cannot borrow *self as mutable because it is also borrowed as immutable


#1

In the following example code, I get the error of “Cannot borrow *self as mutable” on the commented line.

I’ve tried different variations of mut, not mut, borrow(), borrow_mut(), but can’t seem to get around it.

Gotta run but will followup later… help is greatly appreciated. Thanks!

struct Foo {
  context: Rc<RefCell<Context>>
}

impl Foo {
  fn tick(self:&mut Self) {
    //This is the problem line:
    self.render(&self.context.borrow());
  }
}

trait Render {
    fn render(&mut self, context:&Context);
}

impl Render for Foo {
  fn render(self:&mut Self, context:&Context) {
  ...
  }
}

#2

&mut means exclusive mutable access.

&mut self in a method call means it requires exclusive access to all of the object, all its fields, including self.context.

When you borrow &Context you’re creating a paradox:

  • & is a shared immutable access, so you’re promising there is no way for Context to change for as long as &Context exists
  • But you’re promising excursive access to self.context which (as far as the borrow checker can track) allows it to be mutated.

So self.context and the &Context argument can never refer to the same object.

Rust’s borrow checker unfortunately has no way to express “call a method giving it access to some, but not all, fields”.

Some options you have:

  • You could pass &Context to tick as well, and not have self.context at all.
  • Keep using self.context (or pass RefCell<Context> as the argument) and re-borrow each time.
  • Refactor self into two smaller objects, one with the context, used as read-only, and one without, used as mutable.
  • Use &self with &Context argument, and interior mutability for other fields too.

#3

Whoa - another great bullet list :smiley:

Feels like this is an essential sort of thing that pops up fairly often in real-world code?