Rust does compile time check on borrowing rule. But there are some scenarios we need to defer it to runtime. Let me show a simplified version from one of the examples in the book
We have a trait with one method. No change on internal states is allowed inside this method. (&self
is used instead of &mut self
)
pub trait Messenger {
fn send(&self, msg: &str);
}
What if we want to store the messages sent? (e.g. it's common when we create a mock object for testing) It means we need to change the internal states. For some reasons (e.g. it is from 3rd party), we can't modify this trait, so we can't change to &mut self
. Anyway, let's do it first and see what will happen.
struct MyMessenger {
messages: Vec<String>
}
impl MyMessenger {
fn new() -> MyMessenger {
MyMessenger { messages: vec![] }
}
}
impl Messenger for MyMessenger {
fn send(&self, msg: &str) {
self.messages.push(String::from(msg));
}
}
On the line push
method is called, the compiler complains.
cannot borrow `self.messages` as mutable, as it is behind a `&` reference
`self` is a `&` reference, so the data it refers to cannot be borrowed as mutablerustcClick for full compiler diagnostic
main.rs(2, 13): consider changing that to be a mutable reference: `&mut self`
We want to make it passes the compilation. Let's rewrite it with RefCell
.
use std::cell::RefCell;
struct MyMessenger {
messages: RefCell<Vec<String>>
}
impl MyMessenger {
fn new() -> MyMessenger {
MyMessenger { messages: RefCell::new(vec![]) }
}
}
impl Messenger for MyMessenger {
fn send(&self, msg: &str) {
self.messages.borrow_mut().push(String::from(msg));
}
}
We use borrow_mut
to borrow a mutable value. Compilation passes this time.
The borrowing rule is still checked in runtime. Runtime error will occur if we do this.
(This violates the rule "At any given time, we can have either one mutable reference or any number of immutable references".)
let x = RefCell::new(String::from("Hello World"));
let y = x.borrow_mut();
let z = x.borrow(); // Error occurs here in runtime
Top comments (0)