DEV Community

Franz Wong
Franz Wong

Posted on

1

Runtime check on borrowing rule with RefCell

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);
}
Enter fullscreen mode Exit fullscreen mode

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));
    }
}
Enter fullscreen mode Exit fullscreen mode

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`
Enter fullscreen mode Exit fullscreen mode

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));
    }
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Image of Timescale

🚀 pgai Vectorizer: SQLAlchemy and LiteLLM Make Vector Search Simple

We built pgai Vectorizer to simplify embedding management for AI applications—without needing a separate database or complex infrastructure. Since launch, developers have created over 3,000 vectorizers on Timescale Cloud, with many more self-hosted.

Read full post →

Top comments (0)

Image of Docusign

🛠️ Bring your solution into Docusign. Reach over 1.6M customers.

Docusign is now extensible. Overcome challenges with disconnected products and inaccessible data by bringing your solutions into Docusign and publishing to 1.6M customers in the App Center.

Learn more