I am writing a Rogue-like in Rust. I have a Player
which has a Vec
of boxed TimedEffects
. A timed effect has an activate(&mut Player)
and deactivate(&mut Player)
method, and a tick()
method that decrements the time remaining. When it goes to zero, the deactivate()
method should be called.
pub struct Player {
timed_effects: Vec<Box<TimedEffect>>,
}
Each time the player moves, I need to decrement the time remaining. This is done inside a Player
method:
impl Player {
fn regenerate(&mut self) {
self.timed_effects.iter_mut().for_each(|te| te.tick());
for i in 0..self.timed_effects.len() {
if self.timed_effects[i].ticks_remaining() == 0 {
let bte = self.timed_effects.swap_remove(i);
bte.deactivate(self);
}
}
}
}
I originally tried passing the self
parameter (&mut Player
) to the tick()
method of the TimedEffect
objects, with logic to invoke deactivate(player)
automatically when the time went to zero.
Iterating over the vector constitutes a borrow of (Player
) self
, which is incompatible with passing the &mut Player
parameter to tick()
, or even to a separate iteration with .filter
.
Instead, as shown, I find myself iterating over a range of integers, extracting the box from the vector into a local variable, and then invoking .deactivate(self)
on it.
This is painful.
Given the effects need to have some connection with their victim so the deactivate()
method can undo the effect, how should I be architecting these objects so that I don't wind up tangled in this web of dependent borrows?