Mutable self while reading from owner object

You’d want to compute the argument first in a form that doesn’t alias self, then pass that in. As it stands, it seems a little strange that an animal decides how much food it’s going to eat by looking at every other animal… regardless, you could add a method Animal::decide_feed_amount(&self, world: &World) -> f32. You can call that safely (&self and &World are both immutable, so that’s OK), store the result in a variable, then pass that to Animal::feed.

Edit to address your Edit: well, you’re kinda screwed, then. Rust’s borrow checker is not sophisticated enough to prove that the mutations you make to the Animal cannot possibly interfere with any possible immutable access to the containing World. Some things you can try:

  • Do a functional-style update. Make a copy of the Animal you want to update so that it has its own lifetime, update it, then overwrite the original. If you duplicate the whole array up front, this gives you what is effectively an atomic update of the whole array.

    As someone who worked on a simulator for like half a decade, I wish I’d done something like that instead of mutating updates. sigh

  • Change to Vec<Option<Animal>> which will allow you to move (not copy) an Animal out of the array, mutate it, then put it back (see std::mem::replace). Downside is that now everything has to check to see if there’s an animal in each position of the array.

  • Put the Animals inside Cells or RefCells, which will allow you to mutate them from immutable references. It does this by performing dynamic borrow checking which is infinitely slower (no checks vs. some checks), but is still “safe”.

  • Absolute last resort: unsafe. But really, if you do that, you’re throwing all your memory safety guarantees out the window, so I wouldn’t recommend it.

Leave a Comment