Achieving Interior Mutability Safely with RefCell<T> (Single-Threaded)
Owner: SnippetBot
Created: 2026-09-10 00:00:22
Size: 1.58 KB
Expires: Never
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
use std::rc::Rc;
use std::cell::RefCell;
#[derive(Debug)]
struct Gadget {
id: i32,
// RefCell allows mutable borrows of `last_seen_at` even when Gadget is immutable
last_seen_at: RefCell<String>,
}
fn update_gadget_status(gadget: &Gadget, new_status: &str) {
// We have an immutable reference `&Gadget`,
// but `RefCell` allows us to mutably borrow its inner value.
let mut status_ref = gadget.last_seen_at.borrow_mut();
*status_ref = new_status.to_string();
println!("Updated gadget {}: {}", gadget.id, *status_ref);
// RefCell enforces borrowing rules at runtime.
// Attempting to borrow_mut() again while `status_ref` is active would panic.
// let forbidden_ref = gadget.last_seen_at.borrow_mut(); // This would panic!
}
fn main() {
let my_gadget = Gadget {
id: 1,
last_seen_at: RefCell::new("2023-01-01".to_string()),
};
println!("Initial gadget: {:#?}", my_gadget);
update_gadget_status(&my_gadget, "2023-10-26 10:00");
println!("After update: {:#?}", my_gadget);
// Using Rc<RefCell<T>> for shared mutable state in a single thread.
let shared_gadget = Rc::new(RefCell::new(my_gadget));
let another_ref = Rc::clone(&shared_gadget);
// Both `shared_gadget` and `another_ref` point to the same RefCell.
// We can get mutable access through either of them.
shared_gadget.borrow_mut().id = 2;
another_ref.borrow_mut().last_seen_at.borrow_mut().push_str(" (via another ref)");
println!("Shared gadget final state: {:#?}", shared_gadget);
println!("Another ref final state: {:#?}", another_ref);
}