Это в основном дубликат этого вопроса : ваше закрытие сохраняет ссылку на self
(так что он может вызывать self.move_down()
и self.begin_gravity()
), и вы пытаетесь сохранить его внутри self → это невозможно.
Вы можете получить аналогичный эффект, если измените свое закрытие на аргумент &mut Game
и оперируете этим:
pub struct TimestepTimer {
pub frameForExecution: i32,
pub func: Box<dyn Fn(&mut Game) -> ()>
}
pub struct Game {
pub frame: i32,
pub timers: Vec<TimestepTimer>
}
impl Game {
fn add_timer (&mut self, framesFromNow: i32, func: Box<dyn Fn(&mut Game) -> ()>) {
self.timers.push(TimestepTimer {
frameForExecution: self.frame + framesFromNow,
func
});
}
/* Example of a function that would use add_timer */
pub fn begin_gravity(&mut self) {
self.add_timer(30, Box::new(|s: &mut Game| {
// self.move_down();
// Gravity happens repeatedly
s.begin_gravity();
}));
}
// Later on would be a function that checks the frame no.
// and calls the timers' closures which are due
}
Детская площадка
Но теперь у вас возникнут проблемы при вызове таймеров, потому что вам понадобится ссылка на self.timers
для его итерации, и в то же время вам нужно будет передать изменяемую ссылку на self
в замыкания, но компилятор не позволит вам иметь неизменную ссылку на self.timers
и изменяемую ссылку на self
одновременно. Если вы действительно хотите сохранить свои таймеры в Vec
, самый простой способ решить эту проблему - заменить timers
пустым вектором и заполнить его, как вы go:
pub fn step (&mut self) {
self.frame += 1;
let mut timers = vec![];
std::mem::swap (&mut self.timers, &mut timers);
for t in timers {
if self.frame > t.frameForExecution {
(t.func)(self);
} else {
self.timers.push (t);
}
}
}
Детская площадка
Однако, вероятно, было бы лучше хранить таймеры в BinaryHeap
, который позволяет гораздо более чистое и эффективное выполнение l oop:
pub fn step (&mut self) {
self.frame += 1;
while let Some (t) = self.timers.peek() {
if t.frameForExecution >= self.frame { break; }
// `unwrap` is ok here because we know from the `peek` that
// there is at least one timer in `timers`
let t = self.timers.pop().unwrap();
(t.func)(self);
}
}
Детская площадка
Это потребует реализации Ord
вместе с несколькими другими чертами на TimestepTimer
:
impl Ord for TimestepTimer {
fn cmp (&self, other: &Self) -> Ordering {
// Note the swapped order for `self` and `other` so that the `BinaryHeap`
// will return the earlier timers first.
other.frameForExecution.cmp (&self.frameForExecution)
}
}
impl PartialOrd for TimestepTimer {
fn partial_cmp (&self, other: &Self) -> Option<Ordering> {
Some (self.cmp (other))
}
}
impl PartialEq for TimestepTimer {
fn eq (&self, other: &Self) -> bool {
self.frameForExecution == other.frameForExecution
}
}
impl Eq for TimestepTimer {}