I keep running into a common pattern that causes me trouble: when I need to use lookup functions from within a &mut self
function. I'll use my current game bots as an example.
I have a State
class that owns the details of the state. These are broken into several types, such as Item
or Unit
and I have a Vec
of these items (like a Vec<Item>
). This structure seems valid, as this State
logically owns all of this stuff.
I have lookup functions to get at items, such as:
fn find_item<'a>(&'a self, name : &str) -> Option<&'a Item> { ... }
I also have a Turn
type which represents a "change" to the system. I've structured it this way so the Turn
can be created using an immutable reference to the State
. I don't have to worry about any borrowing problems while constructing the turn. However, there comes a point when I must apply the turn, and I have a apply
function for that:
pub fn apply_turn(&mut self, hero : usize, turn : &Turn)
This is where my difficulty starts. The moment I attempt to use any lookup function, like find_item
, I trip up the borrow-checker, since I end up with multiple borrows of the state.
For example, this function (called from apply_turn
):
fn sell_item(&mut self, hero : usize, name : &str ) {
let item = self.find_item(name).unwrap();
self.us.gold += item.cost / 2;
This fails, since find_item
borrows self
and self.us.gold +=
requires a borrow as well (I don't know if that's the right word now).
In this simple case I was forced to call clone()
on the item so I could keep processing. But it's not a workable solution in most cases. Consider that in many functions I'll need to do something like this:
fn apply_bit(&mut self, hero_ndx : usize, ndx : usize ) {
let &mut her = self.lookup_mut_hero(hero_ndx);
let &item = self.lookup_item(ndx);
her.field += item.field;
self.field -= her.field;
}
This type of thing seems completely off-limits due to the borrow checker. But I'm at a total loss as to how I should otherwise accomplish this pattern? In one of my attempts I resorted to using usize
indexes everywhere and refering to the array as needed, never creating any name aliases: but that code is hard to read and maintain due to it.
How do I approach the problem of needing references to items within a mutable state function?