不能一次多次借用可变的

问题描述 投票:0回答:2

我正在尝试用 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()
.

访问内存

我希望问题和代码很清楚。

rust borrow-checker
2个回答
0
投票

方法一:简单方法

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();
}

优点:

非常容易理解和处理

缺点:

有点限制,你必须把东西传来传去。

https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=54836ccd4d8dc091846a2bb64df2d4f4

方法二:使用 Rc

这在设计上也有些幼稚:

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

在这里我们可以传递虚拟机,资源会根据需要尝试可变或不可变地借用适当的资源。

评论

请对我所说的持保留意见(换句话说,不必将我所说的视为“正确”的做事方式)。

我认为您可能应该考虑如何重新设计代码,以便只有一个“协调器”(状态机),而不是说每个组件(例如 CPU)都知道所有其他组件。


0
投票

您可以只传递

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
和内存分开传可能会更好

© www.soinside.com 2019 - 2024. All rights reserved.