Guide

RefCell

Normally you need &mut to change a value, and the compiler checks the borrow rules. RefCell<T> moves that check to run time, so you can change a value through a shared reference.

Interior mutability

A RefCell lets you change what is inside even when you only have & to it. The variable does not need mut.

use std::cell::RefCell;let c = RefCell::new(5);*c.borrow_mut() += 1;println!("{}", c.borrow()); // 6

You can also skip the use line and write the full path, like std::cell::RefCell::new(5).

borrow and borrow_mut

  • c.borrow() gives a Ref<T>, which reads the value.
  • c.borrow_mut() gives a RefMut<T>, which can change it.

These are guards. The borrow lasts until the guard is dropped, often at the end of the line or the block. Use * to reach the value inside a guard.

Rules at run time

The same rules still apply: many readers, or one writer, never both. But RefCell checks them while the program runs. If you break them, the program panics with an "already borrowed" error. The code still compiles.

let c = RefCell::new(1);let r = c.borrow();// c.borrow_mut(); // would panic heredrop(r);*c.borrow_mut() += 1; // fine now

drop(r) drops a value right away, before the end of its block. Here it ends the read borrow early.

try_borrow_mut() returns an Err instead of panicking. is_err() is true when a Result is an Err, just like is_ok() is true for Ok.

Rc<RefCell<T>>

Rc gives many owners but no changes. RefCell gives changes but one owner. Put them together and every owner can change the shared value.

use std::rc::Rc;let a = Rc::new(RefCell::new(vec![1]));let b = Rc::clone(&a);b.borrow_mut().push(2);println!("{:?}", a.borrow()); // [1, 2]

Remember

  • RefCell lets you change a value through &.
  • borrow() reads, borrow_mut() writes.
  • Breaking the rules is a panic at run time, not a compile error.
  • Rc<RefCell<T>> means shared owners who can all change the value.