rust two objects refering each borrow_mut pattern

116 Views Asked by At

A similar question I posted earlier is here Rust can't modify RefCell in Rc, but completely different.


I want to simulate some natural process, so I have a Simulator, and a reactor like a NuclearReactor. The simulator will modify the reactor, and the reactor can reversely influance the simulator by modifying it. One important thing is that the NuclearReactor is wrapped from somewhere else, the solid_function must has a inmutable &self.

So after reading rust book of RefCell, I wrote something like these, It complies, but crashed.

use std::borrow::BorrowMut;
use std::cell::RefCell;
use std::rc::{Rc, Weak};

pub struct Simulator {
    nr: NuclearReactor,
    data: Vec<f64>,
}

impl Simulator {
    pub fn on_nuclear_data(&mut self, x: i64) {
        // modify self
    }
    pub fn run_simulation(&mut self) {
        self.nr.write_simulator();
    }
}

pub struct NuclearReactor {
    simulator: Option<Weak<RefCell<Simulator>>>,
}

impl NuclearReactor {
    pub fn solid_function(&self, x: i64) {
        /*
        this function `&self` is solid, so I have to use a RefCell to wrap Simulator
         */
    }

    pub fn write_simulator(&self) {
        /*
        thread 'main' panicked at 'already borrowed: BorrowMutError'
        */
        (*self.simulator.as_ref().unwrap().upgrade().unwrap()).borrow_mut().on_nuclear_data(0);
    }
}

pub fn main() {
    let nr_ = NuclearReactor {
        simulator: None
    };

    let mut sm_ = Rc::new(RefCell::new(Simulator {
        nr: nr_,
        data: vec![],
    }));


    (*sm_).borrow_mut().nr.simulator = Some(Rc::downgrade(&sm_));
    (*sm_).borrow_mut().run_simulation();
}

Obviously, the runtime check of borrow_mut fails.

Actually the NuclearReactor is my online code, the Simulator is an offline test, so I wanna modify the NuclearReactor at a minimal cost to let it run on the offline environment. That's why I have to keep the function solid_function with an immutable &self. Changing it to a &mut self is and then move to-modifying objects to a seperate function is feasible, but then I have to modify the online code frequently at a high cost. It there anything cool that can solve it ?

1

There are 1 best solutions below

0
On

Ok, after reading this: http://smallcultfollowing.com/babysteps/blog/2018/11/01/after-nll-interprocedural-conflicts/

I finnaly realized that what I am doing is something like below and rust was helping me avoiding bugs.

let v: Vec<i64> = vec![1,2,3];
for ele in v.iter_mut(){
    v.push(1);
}

Thankfully, pushing NuclearReactor's modify to a temp buffer then apply them to Simulator is just enough to solve my problem.

Also, I didn't explain the question clearly (actually I didn't get the point to describe the question until I solved it), so the community can't help me.