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);
This is because &Option<T>
cannot be unwrap
ped.
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
.