Borrow checker help... I should know this by now

I have a world that contains an observer. I would like to tick the world. When the world ticks it should call tick on the observer. When the observer ticks it should be able to update its internal state and read other state from the world.

I think this describes what I want pretty well:

struct World {
    observer: Observer,
}

struct Observer {
}

impl World {
    fn tick(&mut self) {
        self.observer.tick(self);
    }
}

impl Observer {
    fn tick(&mut self, _world: &World) {
    }
}

(Playground)

I think I understand why the borrow checker doesn’t like this.

At the same time and object updating its internal state with a read only reference to its container seems like it should be possible? What do I need to do to make rust agree?

You can refactor your code a bit,

struct World {
    observer: Observer,
    state: State
}

struct Observer { ... }
struct State { ... }

impl World {
    fn tick(&mut self) {
        self.observer.tick(&self.state)
    }
}

impl Observer {
    fn tick(&mut self, state: &State) { ... }
}

World should contain nothing other than those two fields, everything else should be factored into either State or Observer.

The problem is that Observer needs a unique reference to itself to tick, but that unique reference will be aliased by the shared reference to World when you pass that to Observer::tick. Obviously you can’t have an aliased unique reference, that doesn’t even make sense.

(note: that you can read more about thinking of &mut T as a unique reference and &T as a shared reference here, this way of thinking of reference is how the Rust compiler thinks of reference, so it would be good to learn to think this way instead of in terms of read and write references)

1 Like