我正在尝试用 Rust 构建一个 CHIP-8 模拟器来学习语言。我目前正试图解决编译器给我在标题中写的这个错误。
我将描述模拟器的当前结构,然后我将指出它失败的地方。
首先我有
VM
结构定义如下
pub struct VM {
cpu: CPU,
memory: Memory
}
然后我有一个
CPU
结构,它有一个定义为的方法
pub fn execute(&mut self, vm: &mut VM) -> Result<(), &'static str> {
// ....
}
最后失败的方法是
VM::cpu_execute
定义为这个
pub fn cpu_execute(&mut self) -> Result<(), &'static str> {
self.cpu.execute(&mut self)
}
这就是它失败的地方。
我理解错误本身,但在这种情况下我真的不知道如何解决它。 代码看起来像这样的原因是 CPU 和其他 VM 模块可以通信:例如 CPU 可以通过执行
vm.memory() / vm.memory_mut()
. 访问内存
我希望问题和代码很清楚。
This approach says pass the bits that are mutating separately (e.g. if your CPU is mutating the memory of the VM, just pass that to the execute):
#[derive(Default, Debug)]
struct CPU;
#[derive(Default, Debug)]
struct Memory { data: Vec<u8> }
#[derive(Default, Debug)]
pub struct VM {
cpu: CPU,
memory: Memory
}
impl CPU {
pub fn execute(&mut self, mem: &mut Memory) -> Result<(), &'static str> {
println!("Executing");
mem.data = b"deadbeaf".to_vec();
Ok(())
}
}
impl VM {
pub fn run(&mut self) {
self.cpu.execute(&mut self.memory);
println!("CPU changed memory to {:#?}", self.memory);
}
}
pub fn main() {
let mut vm = VM::default();
vm.run();
}
非常容易理解和处理
有点限制,你必须把东西传来传去。
这在设计上也有些幼稚:
use std::rc::Rc;
use std::cell::RefCell;
#[derive(Default, Debug)]
struct CPU {
ip: u8, // instruction pointer
r1: u8, // register 1
r2: u8, // register 2
}
#[derive(Default, Debug)]
struct Memory { data: Vec<u8> }
#[derive(Default, Debug)]
pub struct VM {
cpu: Rc<RefCell<CPU>>,
memory: Rc<RefCell<Memory>>
}
impl CPU {
pub fn execute(&mut self, vm: &VM) -> Result<(), &'static str> {
println!("Executing");
let mut mem = vm.memory.borrow_mut();
mem.data = b"deadbeaf".to_vec();
self.ip += 1; // increments instruction pointer.
Ok(())
}
}
impl VM {
pub fn run(&self) {
let mut cpu = self.cpu.borrow_mut();
cpu.execute(&self).unwrap();
println!("CPU changed memory to {:#?}", self.memory);
}
}
pub fn main() {
let vm = VM::default();
println!("VM: {:#?}", vm);
vm.run();
println!("VM: {:#?}", vm);
}
在这里我们可以传递虚拟机,资源会根据需要尝试可变或不可变地借用适当的资源。
请对我所说的持保留意见(换句话说,不必将我所说的视为“正确”的做事方式)。
我认为您可能应该考虑如何重新设计代码,以便只有一个“协调器”(状态机),而不是说每个组件(例如 CPU)都知道所有其他组件。
您可以只传递
VM
(将其设为关联方法)并通过VM访问CPU:
pub fn execute(vm: &mut VM) -> Result<(), &'static str> {
// ....
}
pub fn cpu_execute(&mut self) -> Result<(), &'static str> {
CPU::execute(self)
}
但是把
&mut self
和内存分开传可能会更好