我在Rust中写了一个像Rogue一样的东西。我的Player
Vec
盒装TimedEffects
。定时效果包含activate(&mut Player)
和deactivate(&mut Player)
方法,以及减少剩余时间的tick()
方法。当它变为零时,应该调用deactivate()
方法。
pub struct Player {
timed_effects: Vec<Box<TimedEffect>>,
}
每次玩家移动时,我都需要减少剩余的时间。这是在Player
方法内完成的:
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);
}
}
}
}
我最初尝试将self
参数(&mut Player
)传递给tick()
对象的TimedEffect
方法,并使用逻辑自动调用deactivate(player)
时间变为零。
迭代向量构成了对(Player
)self
的借用,这与将&mut Player
参数传递给tick()
不兼容,甚至与单独的迭代无关.filter
。
相反,如图所示,我发现自己迭代一系列整数,将向量中的框提取为局部变量,然后在其上调用.deactivate(self)
。
这很痛苦。
鉴于效果需要与受害者建立联系,因此deactivate()
方法可以撤消效果,我应该如何构建这些对象,以便我不会在这个依赖借用网络中纠结?
答案 0 :(得分:2)
为避免借用问题,您可以分两步完成:
timed_effects
完成的效果传输到缓冲区deactivate
。我会使用夜间Vec::drain_filter
来获取更加流畅的代码,但它肯定不是强制性的。
fn regenerate(&mut self) {
self.timed_effects.iter_mut().for_each(|te| te.tick());
let timed_out: Vec<_> =
self.timed_effects
.drain_filter(|t| t.ticks_remaining() == 0)
.collect();
// Split iteration in a second step to stop borrowing self.
for timer in timed_out {
timer.deactivate(self);
}
}
为了进一步提高效率,您可以将可重用缓冲区传递给regenerate
(以避免分配)。