Cannot borrow as mutable because it is also borrowed as immutable

Hi every one, I'm not very new to rust, but I still feel confused with borrow check. The code is really simple below:

struct CPU<'a, 'b> {
    reg: Vec<u8>,
    read_callback: Box<dyn 'a + Fn(u8) -> u8>,
    write_callback: Box<dyn 'b + FnMut(u8, u8)>
}

struct Memory {
    ram: Vec<u8>
}


fn main() {

    let mut mem = Memory {ram: vec![0; 256]};
    let mut cpu = CPU {
        reg: vec![0; 4],
        read_callback: Box::new(|address| {mem.ram[address as usize]}),
        write_callback: Box::new(|address, data| {mem.ram[address as usize] = data;})
    };

    cpu.read_callback.as_ref()(1);
    cpu.write_callback.as_mut()(1,1);
}

surely the error is: cannot borrow mem as mutable because it is also borrowed as immutable

I wonder how can I make the code runable?

An ordinary mutable reference must have exclusive access to the value it points at, but this is violated in your code as the read_callback also has access. To obtain mutable shared access, you must use what is known as interior mutability. One way to do it is the following:

use std::cell::RefCell;

struct CPU<'a, 'b> {
    reg: Vec<u8>,
    read_callback: Box<dyn 'a + Fn(u8) -> u8>,
    write_callback: Box<dyn 'b + FnMut(u8, u8)>
}

struct Memory {
    ram: RefCell<Vec<u8>>,
}

impl Memory {
    pub fn get(&self, i: usize) -> u8 {
        self.ram.borrow()[i]
    }
    pub fn set(&self, i: usize, val: u8) {
        self.ram.borrow_mut()[i] = val;
    }
}

fn main() {

    let mem = Memory {ram: RefCell::new(vec![0; 256])};
    let mut cpu = CPU {
        reg: vec![0; 4],
        read_callback: Box::new(|address| mem.get(address as usize)),
        write_callback: Box::new(|address, data| {mem.set(address as usize, data);})
    };

    cpu.read_callback.as_ref()(1);
    cpu.write_callback.as_mut()(1,1);
}

This uses a shared reference instead of an unique reference, but RefCell guarantees that Memory is not accessed from multiple threads at the same time, which makes shared mutation safe.

4 Likes

:+1: :+1: :+1: