Module rc
Single-threaded reference-counting pointers. 'Rc' stands for 'Reference Counted'.
The type [Rc<T>]Rc provides shared ownership of a value of type T,
allocated in the heap. Invoking clone on Rc produces a new
pointer to the same allocation in the heap. When the last Rc pointer to a
given allocation is destroyed, the value stored in that allocation (often
referred to as "inner value") is also dropped.
Shared references in Rust disallow mutation by default, and Rc
is no exception: you cannot generally obtain a mutable reference to
something inside an Rc. If you need mutability, put a Cell
or RefCell inside the Rc; see an example of mutability
inside an Rc.
Rc uses non-atomic reference counting. This means that overhead is very
low, but an Rc cannot be sent between threads, and consequently Rc
does not implement Send. As a result, the Rust compiler
will check at compile time that you are not sending Rcs between
threads. If you need multi-threaded, atomic reference counting, use
sync::Arc.
The downgrade method can be used to create a non-owning
Weak pointer. A Weak pointer can be upgraded
to an Rc, but this will return None if the value stored in the allocation has
already been dropped. In other words, Weak pointers do not keep the value
inside the allocation alive; however, they do keep the allocation
(the backing store for the inner value) alive.
A cycle between Rc pointers will never be deallocated. For this reason,
Weak is used to break cycles. For example, a tree could have strong
Rc pointers from parent nodes to children, and Weak pointers from
children back to their parents.
Rc<T> automatically dereferences to T (via the Deref trait),
so you can call T's methods on a value of type [Rc<T>]Rc. To avoid name
clashes with T's methods, the methods of [Rc<T>]Rc itself are associated
functions, called using fully qualified syntax:
use Rc;
let my_rc = new;
let my_weak = downgrade;
Rc<T>'s implementations of traits like Clone may also be called using
fully qualified syntax. Some people prefer to use fully qualified syntax,
while others prefer using method-call syntax.
use Rc;
let rc = new;
// Method-call syntax
let rc2 = rc.clone;
// Fully qualified syntax
let rc3 = clone;
[Weak<T>]Weak does not auto-dereference to T, because the inner value may have
already been dropped.
Cloning references
Creating a new reference to the same allocation as an existing reference counted pointer
is done using the Clone trait implemented for [Rc<T>]Rc and [Weak<T>]Weak.
use Rc;
let foo = new;
// The two syntaxes below are equivalent.
let a = foo.clone;
let b = clone;
// a and b both point to the same memory location as foo.
The Rc::clone(&from) syntax is the most idiomatic because it conveys more explicitly
the meaning of the code. In the example above, this syntax makes it easier to see that
this code is creating a new reference rather than copying the whole content of foo.
Examples
Consider a scenario where a set of Gadgets are owned by a given Owner.
We want to have our Gadgets point to their Owner. We can't do this with
unique ownership, because more than one gadget may belong to the same
Owner. Rc allows us to share an Owner between multiple Gadgets,
and have the Owner remain allocated as long as any Gadget points at it.
use Rc;
If our requirements change, and we also need to be able to traverse from
Owner to Gadget, we will run into problems. An Rc pointer from Owner
to Gadget introduces a cycle. This means that their
reference counts can never reach 0, and the allocation will never be destroyed:
a memory leak. In order to get around this, we can use Weak
pointers.
Rust actually makes it somewhat difficult to produce this loop in the first
place. In order to end up with two values that point at each other, one of
them needs to be mutable. This is difficult because Rc enforces
memory safety by only giving out shared references to the value it wraps,
and these don't allow direct mutation. We need to wrap the part of the
value we wish to mutate in a RefCell, which provides interior
mutability: a method to achieve mutability through a shared reference.
RefCell enforces Rust's borrowing rules at runtime.
use Rc;
use Weak;
use RefCell;