use std::cell::RefCell; use std::rc::Rc; // Often used with RefCell to share ownership in single-threaded scenarios // A 'Node' in a graph-like structure where its value might need to be // mutated even when accessed through an immutable reference (e.g., during graph traversal). #[derive(Debug)] struct GraphNode { id: u32, value: RefCell, // Allows mutable access to `value` through an immutable `&GraphNode` // In a real graph, you might have `children: Vec>` } impl GraphNode { fn new(id: u32, initial_value: u32) -> Self { GraphNode { id, value: RefCell::new(initial_value), } } // Increment the node's value. This method takes `&self` (an immutable reference), // but can still mutate `self.value` thanks to `RefCell`. fn increment_value(&self, amount: u32) { // `borrow_mut()` gets a mutable reference to the inner value. // This check happens at runtime. If another mutable borrow or any // shared borrows exist, it will panic. This prevents data races in single-threaded contexts. let mut val = self.value.borrow_mut(); // Runtime borrow check *val += amount; println!("Node {} value incremented to: {}", self.id, *val); // `val` (the mutable borrow) is automatically dropped here, releasing the runtime lock. } // Get the current value. Takes `&self`, but safely accesses the inner value. fn get_value(&self) -> u32 { // `borrow()` gets an immutable reference to the inner value. // Panics if a mutable borrow is currently active. *self.value.borrow() // Runtime borrow check } } fn main() { println!("--- Demonstrating RefCell for interior mutability ---"); let node1 = GraphNode::new(1, 10); println!("Initial node1: {:?}", node1); node1.increment_value(5); // Mutating through an immutable reference println!("Node1 after increment: {:?}", node1); node1.increment_value(2); println!("Node1 after another increment: {:?}", node1); // Example of a runtime borrow error (uncomment to see panic) /* let mut_ref_1 = node1.value.borrow_mut(); println!("Acquired first mutable ref."); // This will panic because `mut_ref_1` is still active // let mut_ref_2 = node1.value.borrow_mut(); // println!("Acquired second mutable ref."); */ // Using Rc with RefCell to share mutable nodes in a single-threaded graph-like structure let node_a = Rc::new(GraphNode::new(101, 100)); let node_b = Rc::clone(&node_a); // node_b is another `Rc` pointing to the same `GraphNode` println!(" Shared Node A value: {}", node_a.get_value()); println!("Shared Node B value: {}", node_b.get_value()); node_a.increment_value(10); // Mutate through node_a's Rc handle println!("Node A value after mutation: {}", node_a.get_value()); println!("Node B value (reflects A's mutation): {}", node_b.get_value()); // Without RefCell, if GraphNode::value was just u32, you couldn't // mutate it via `&self` or via shared `Rc` references. }