Rc<RefCell<T>> combines shared ownership with checked interior mutation for single-threaded state.

Program

Play the program to choose an event and append it through a cloned owner.

event
rc_refcell_log.rs
Replay: real traced execution (multi-file project)
use std::cell::RefCell;
use std::rc::Rc;

fn main() {
    let event = "render";
    let log = Rc::new(RefCell::new(Vec::new()));
    let worker = Rc::clone(&log);
    record(&log, "start");
    record(&worker, event);
    let joined = log.borrow().join(",");
    println!("{} owners={}", joined, Rc::strong_count(&log));
}

fn record(log: &Rc<RefCell<Vec<&'static str>>>, event: &'static str) {
    log.borrow_mut().push(event);
}
use std::cell::RefCell;
use std::rc::Rc;

fn main() {
    let event = "trace";
    let log = Rc::new(RefCell::new(Vec::new()));
    let worker = Rc::clone(&log);
    record(&log, "start");
    record(&worker, event);
    let joined = log.borrow().join(",");
    println!("{} owners={}", joined, Rc::strong_count(&log));
}

fn record(log: &Rc<RefCell<Vec<&'static str>>>, event: &'static str) {
    log.borrow_mut().push(event);
}
use std::cell::RefCell;
use std::rc::Rc;

fn main() {
    let event = "publish";
    let log = Rc::new(RefCell::new(Vec::new()));
    let worker = Rc::clone(&log);
    record(&log, "start");
    record(&worker, event);
    let joined = log.borrow().join(",");
    println!("{} owners={}", joined, Rc::strong_count(&log));
}

fn record(log: &Rc<RefCell<Vec<&'static str>>>, event: &'static str) {
    log.borrow_mut().push(event);
}
  1. event ← "render", log ← RefCell { value: [] }, worker ← RefCell { value: [] }

    4fn main() {5    let even→ "render"t = "render"; //@event="render", "trace", "publish"6    let lo→ RefCell { value: [] }g = Rc::new(RefCell::new(Vec::new()));7    let worke→ RefCell { value: [] }r = Rc::clone(&loRefCell { value: [] }g);8    record(&log, "start");
  2. fn record(log: &Rc<RefCell<Vec<&'static str>>>, event: &'static str)

    pass 1 of 2
    14fn record(log: &Rc<RefCell<Vec<&'static str>>>, event: &'static str) {15    log.borrow_mut().push(event);16}
  3. joined ← "start,render"

    pass 2 of 2
    9    record(&worker, event);10    let joine→ "start,render"d = log.borrow().join(",");11    println!("{} owners={}", joined, Rc::strong_count(&log));12}1314fn record(log: &Rc<RefCell<Vec<&'static str>>>, event: &'static str) {15    log.borrow_mut().push(event);16}
    outputstart,render owners=2
  1. event ← "trace", log ← RefCell { value: [] }, worker ← RefCell { value: [] }

    4fn main() {5    let even→ "trace"t = "trace";6    let lo→ RefCell { value: [] }g = Rc::new(RefCell::new(Vec::new()));7    let worke→ RefCell { value: [] }r = Rc::clone(&loRefCell { value: [] }g);8    record(&log, "start");
  2. fn record(log: &Rc<RefCell<Vec<&'static str>>>, event: &'static str)

    pass 1 of 2
    14fn record(log: &Rc<RefCell<Vec<&'static str>>>, event: &'static str) {15    log.borrow_mut().push(event);16}
  3. joined ← "start,trace"

    pass 2 of 2
    9    record(&worker, event);10    let joine→ "start,trace"d = log.borrow().join(",");11    println!("{} owners={}", joined, Rc::strong_count(&log));12}1314fn record(log: &Rc<RefCell<Vec<&'static str>>>, event: &'static str) {15    log.borrow_mut().push(event);16}
    outputstart,trace owners=2
  1. event ← "publish", log ← RefCell { value: [] }, worker ← RefCell { value: [] }

    4fn main() {5    let even→ "publish"t = "publish";6    let lo→ RefCell { value: [] }g = Rc::new(RefCell::new(Vec::new()));7    let worke→ RefCell { value: [] }r = Rc::clone(&loRefCell { value: [] }g);8    record(&log, "start");
  2. fn record(log: &Rc<RefCell<Vec<&'static str>>>, event: &'static str)

    pass 1 of 2
    14fn record(log: &Rc<RefCell<Vec<&'static str>>>, event: &'static str) {15    log.borrow_mut().push(event);16}
  3. joined ← "start,publish"

    pass 2 of 2
    9    record(&worker, event);10    let joine→ "start,publish"d = log.borrow().join(",");11    println!("{} owners={}", joined, Rc::strong_count(&log));12}1314fn record(log: &Rc<RefCell<Vec<&'static str>>>, event: &'static str) {15    log.borrow_mut().push(event);16}
    outputstart,publish owners=2
Rc `Rc` gives multiple owners of the same single-threaded value.
RefCell `RefCell` checks borrow rules at runtime so the log can be mutated through shared owners.
shared log Both `log` and `worker` point to the same vector, so both records appear together.