方法一:简单方法
这种方法表示传递单独变异的位(例如,如果您的 CPU 正在变异 VM 的内存,只需将其传递给执行):
#[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();
}
优点:
非常容易理解和处理
缺点:
有些有限,你必须传递这些东西。
https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=54836ccd4d8dc091846a2bb64df2d4f4
方法二:使用 Rc<RefCell>
这在设计上也有些幼稚:
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);
}
https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=725587bae3d71159fe94530ac8542e68
在这里,我们能够传递 VM,并且资源会根据需要尝试借用适当的可变或不可变资源。
评论
请对我所说的持保留意见(换句话说,不必将我所说的视为“正确”的做事方式)。
我认为您可能应该考虑如何重新设计代码,以便只有一个“协调器”(状态机),而不是说每个组件(例如 CPU)都知道所有其他组件。