在拥有这些函数的结构上应用一些函数

Apply some functions on a struct owning those functions

我想在拥有这些函数的结构上应用一些函数。

第一次尝试:

struct VM {
    buffer: Vec<fn(&mut VM)>,
    stack: Vec<isize>,
}

impl VM {
    fn new() -> VM {
        VM {
            buffer: vec![VM::op_zero, VM::op_drop],
            stack: vec![],
        }
    }
    fn op_zero(&mut self) { self.stack.push(0); }
    fn op_drop(&mut self) {
        match self.stack.pop() {
            Some(i) => println!("drop {}", i),
            None => println!("stack underflow!")
        }
    }
    fn evaluate(&mut self) {
        for op in self.buffer {
            op(self);
        }
    }
}

fn main() {
    let mut vm = VM::new();
    vm.evaluate();
}

这不起作用,因为移出了借来的内容。我在self.buffer前加了一个&,还是不行,因为self.buffer也是借来的不可变

fn evaluate(&mut self) {
    for op in &self.buffer {
        op(self);
    }
}

第三次尝试有效,但有运行时边界检查数组索引的开销:

fn evaluate(&mut self) {
    let len = self.buffer.len();
    for i in 0..len {
        let op = self.buffer[i];
        op(self);
    }
}

有没有更好的方法来绕过借用检查器?

你真的不应该 "work around the borrow checker"。它阻止您这样做,因为不能保证您调用的 ops 不会弄乱您试图迭代的缓冲区。事实上,你的最终代码有同样的问题:一个 op 可以 截断 缓冲区,当你试图读取超过向量的末尾时导致恐慌。

一种安全的方法是在评估时换掉 buffer。假设您不打算多次评估相同的指令序列:

fn evaluate(&mut self) {
    use std::mem;
    for op in mem::replace(&mut self.buffer, vec![]) {
        op(self);
    }
}

在这种情况下,调用的 op 可以修改新缓冲区,而不会干扰 evaluate