如何在 HashMap 中存储方法指针并调用它们

How to store method pointers in a HashMap and call them

我正在尝试编写一个 chip8 模拟器,但借用检查器让我很为难。

我的想法是通过在 HashMap 中查找方法指针然后执行该方法指针来解码操作码,但我无法使可变方法指针正常工作:

struct Chip8 {
    opcode: u16,
    //... other fields
    jump_table: HashMap<u16, Box<fn(&mut Chip8)>>,
}

使用指针的函数:

fn execute_decoded(&mut self, key: u16) {
    let func = self.jump_table.get(&key);

    match func {
        Some(func) => func(self),
        None => {
            println!("invalid op: {}", self.opcode);
            sleep(Duration::from_millis(10000));
            return;
        }
    }();

    self.program_counter = self.program_counter + 2;
}

检查员抱怨:

 cannot borrow `*self` as mutable because `self.jump_table` is also borrowed as immutable
   --> main.rs:168:36
    |
165 |             let func = self.jump_table.get(&key);
    |                        --------------- immutable borrow occurs here
...
168 |                 Some(func) => func(self),
    |                                    ^^^^ mutable borrow occurs here
...
178 |     }
    |     - immutable borrow ends here

我不明白为什么会出现这个错误。

为什么要 self.jump_table.get(&key) 借钱?基于 execute_decoded 的签名,我假设它适用于 self 的可变借用版本,不需要额外借用。

Rust 中的 HashMap 拥有其中的所有内容。为了得到你的函数指针,你用 let func = self.jump_table.get(&key); 借用它。所以现在,func 不变地借用 self.jump_table(这是 self 的一个元素)。

问题是您正试图将所有 self 传递给 func。如果您不可变地传入 self 就没问题,因为您可以不可变地借用 self 任意多次。但是,由于您试图可变地借用 self,编译器将不允许您这样做,因为您刚刚不变地借用了 self 部分 (特别是 self.jump_table).

解决此问题的一种方法是将您的 Chip8 结构拆分为更小的结构,这样您就可以将所有必要的信息传递给 func 而无需传递 jump_table .

没有理由 Box HashMap 中的函数指针,这只会引入不必要的间接寻址。

一样,您正在借用函数指针。问题是,没有理由这样做。您可以只复制函数指针以将其与 HashMap:

解除关联
use std::collections::HashMap;

struct Chip8 {
    jump_table: HashMap<u16, fn(&mut Chip8)>,
}

impl Chip8 {
    fn execute_decoded(&mut self, key: u16) {
        let func = self.jump_table.get(&key).map(|x| *x);

        match func {
            Some(func) => func(self),
            None => {
                println!("invalid op");
            }
        };
    }
}

fn main() {}