rustrcrefcell

Rust can't modify RefCell in Rc


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:


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) {}
}

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) {
        /*
        none of the two following snippets will work
         */

        /* snippet1: compiler says:
error[E0507]: cannot move out of an `Rc`
  --> src/main.rs:87:17
   |
87 |         let t = *self.simulator.unwrap().upgrade().unwrap();
   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |                 |
   |                 move occurs because value has type `RefCell<Simulator>`, which does not implement the `Copy` trait
   |                 help: consider borrowing here: `&*self.simulator.unwrap().upgrade().unwrap()`

        */
        let t = *self.simulator.unwrap().upgrade().unwrap();
        t.borrow_mut().on_nuclear_data(0);

        /*
         snippet2: compiler says:
error[E0599]: no method named `on_nuclear_data` found for mutable reference `&mut Rc<RefCell<Simulator>>` in the current scope
   --> src/main.rs:101:65
    |
101 |         self.simulator.unwrap().upgrade().unwrap().borrow_mut().on_nuclear_data(0);
    |                                                                 ^^^^^^^^^^^^^^^ method not found in `&mut Rc<RefCell<Simulator>>`

         */
        // self.simulator.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_));
}

But it won't compile. How should I solve it.


Oh... the compile hints me solved it. But it seems complicated. Can anyone explain that, or give a better pattern? I think the pattern is common.

        let t = &*self.simulator.as_ref().unwrap().upgrade().unwrap();
        t.borrow_mut().on_nuclear_data(0);

Actually it should be:

    (*self.simulator.as_ref().unwrap().upgrade().unwrap()).borrow_mut().on_nuclear_data(0);


Solution

  • This is because &Option<T> cannot be unwrapped.

    self.simulator, where self is a &Self, gets a &Option<Weak<RefCell<Simulator>>>.

    Option<T>::unwrap consumes the self and return the inner value by 'move'.

    Option<T>::as_ref converts &self into an Option<&T> safely so that you can unwrap into a &T.