Guide

Rc

Sometimes one value needs more than one owner. For example, two lists might share the same tail. Rc<T> (reference counted) makes that possible in single-threaded code.

Shared ownership

Rc::new(x) puts x on the heap behind a counter. Every Rc that points to it is an owner. An Rc still moves on plain assignment, so use Rc::clone to add an owner.

use std::rc::Rc;let a = Rc::new(String::from("hi"));let b = Rc::clone(&a);println!("{a} {b}"); // hi hi

Rc::clone

Rc::clone(&a) does not copy the String. It copies a pointer and adds 1 to the counter, so it is cheap. a.clone() does the same thing, but Rc::clone makes it clear that no deep copy happens. Rc::ptr_eq(&a, &b) is true when a and b point at the very same value, not just equal ones.

Reference counting

Rc::strong_count(&a) tells you how many owners exist right now. When an owner is dropped, the count goes down by 1. When it reaches zero, the value inside is dropped.

let a = Rc::new(5);{    let b = Rc::clone(&a);    println!("{}", Rc::strong_count(&a)); // 2}println!("{}", Rc::strong_count(&a)); // 1

Rc is read-only

Many owners could be reading the value at once. So an Rc only gives shared (&) access. Trying to change the value, like calling push, fails with E0596, even if the variable is mut.

let v = Rc::new(vec![1, 2]);println!("{}", v.len()); // reading is fine// v.push(3);            // error E0596

The next unit shows how to change shared data with RefCell.

Remember

  • Rc gives a value many owners.
  • Rc::clone is cheap: it only bumps a counter.
  • The value is dropped when the count reaches zero.
  • You can read through an Rc, but not change the value (E0596).