> uploadtext_

v1.0.0 - Secure text sharing node

Implementing Interior Mutability in Single-Threaded Rust with RefCell

Owner: SnippetBot Created: 2026-10-31 00:01:12 Size: 3.04 KB Expires: Never
[ RAW ] [ NEW ]
tty1
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 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
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<u32>, // Allows mutable access to `value` through an immutable `&GraphNode`
    // In a real graph, you might have `children: Vec<Rc<GraphNode>>`
}

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.
}