Expand description
Single-threaded reference-counting pointers. ‘Rc’ stands for ‘ReferenceCounted’.
The typeRc<T> provides shared ownership of a value of typeT,allocated in the heap. Invokingclone onRc produces a newpointer to the same allocation in the heap. When the lastRc pointer to agiven allocation is destroyed, the value stored in that allocation (oftenreferred to as “inner value”) is also dropped.
Shared references in Rust disallow mutation by default, andRcis no exception: you cannot generally obtain a mutable reference tosomething inside anRc. If you need mutability, put aCellorRefCell inside theRc; seean example of mutabilityinside anRc.
Rc uses non-atomic reference counting. This means that overhead is verylow, but anRc cannot be sent between threads, and consequentlyRcdoes not implementSend. As a result, the Rust compilerwill checkat compile time that you are not sendingRcs betweenthreads. If you need multi-threaded, atomic reference counting, usesync::Arc.
Thedowngrade method can be used to create a non-owningWeak pointer. AWeak pointer can beupgradedto anRc, but this will returnNone if the value stored in the allocation hasalready been dropped. In other words,Weak pointers do not keep the valueinside the allocation alive; however, theydo keep the allocation(the backing store for the inner value) alive.
A cycle betweenRc pointers will never be deallocated. For this reason,Weak is used to break cycles. For example, a tree could have strongRc pointers from parent nodes to children, andWeak pointers fromchildren back to their parents.
Rc<T> automatically dereferences toT (via theDeref trait),so you can callT’s methods on a value of typeRc<T>. To avoid nameclashes withT’s methods, the methods ofRc<T> itself are associatedfunctions, called usingfully qualified syntax:
Rc<T>’s implementations of traits likeClone may also be called usingfully qualified syntax. Some people prefer to use fully qualified syntax,while others prefer using method-call syntax.
usestd::rc::Rc;letrc = Rc::new(());// Method-call syntaxletrc2 = rc.clone();// Fully qualified syntaxletrc3 = Rc::clone(&rc);Weak<T> does not auto-dereference toT, because the inner value may havealready been dropped.
§Cloning references
Creating a new reference to the same allocation as an existing reference counted pointeris done using theClone trait implemented forRc<T> andWeak<T>.
usestd::rc::Rc;letfoo = Rc::new(vec![1.0,2.0,3.0]);// The two syntaxes below are equivalent.leta = foo.clone();letb = Rc::clone(&foo);// a and b both point to the same memory location as foo.TheRc::clone(&from) syntax is the most idiomatic because it conveys more explicitlythe meaning of the code. In the example above, this syntax makes it easier to see thatthis code is creating a new reference rather than copying the whole content of foo.
§Examples
Consider a scenario where a set ofGadgets are owned by a givenOwner.We want to have ourGadgets point to theirOwner. We can’t do this withunique ownership, because more than one gadget may belong to the sameOwner.Rc allows us to share anOwner between multipleGadgets,and have theOwner remain allocated as long as anyGadget points at it.
usestd::rc::Rc;structOwner { name: String,// ...other fields}structGadget { id: i32, owner: Rc<Owner>,// ...other fields}fnmain() {// Create a reference-counted `Owner`.letgadget_owner: Rc<Owner> = Rc::new( Owner { name:"Gadget Man".to_string(), } );// Create `Gadget`s belonging to `gadget_owner`. Cloning the `Rc<Owner>` // gives us a new pointer to the same `Owner` allocation, incrementing // the reference count in the process.letgadget1 = Gadget { id:1, owner: Rc::clone(&gadget_owner), };letgadget2 = Gadget { id:2, owner: Rc::clone(&gadget_owner), };// Dispose of our local variable `gadget_owner`.drop(gadget_owner);// Despite dropping `gadget_owner`, we're still able to print out the name // of the `Owner` of the `Gadget`s. This is because we've only dropped a // single `Rc<Owner>`, not the `Owner` it points to. As long as there are // other `Rc<Owner>` pointing at the same `Owner` allocation, it will remain // live. The field projection `gadget1.owner.name` works because // `Rc<Owner>` automatically dereferences to `Owner`.println!("Gadget {} owned by {}", gadget1.id, gadget1.owner.name);println!("Gadget {} owned by {}", gadget2.id, gadget2.owner.name);// At the end of the function, `gadget1` and `gadget2` are destroyed, and // with them the last counted references to our `Owner`. Gadget Man now // gets destroyed as well.}If our requirements change, and we also need to be able to traverse fromOwner to Gadget, we will run into problems. AnRc pointer fromOwnertoGadget introduces a cycle. This means that theirreference counts can never reach 0, and the allocation will never be destroyed:a memory leak. In order to get around this, we can useWeakpointers.
Rust actually makes it somewhat difficult to produce this loop in the firstplace. In order to end up with two values that point at each other, one ofthem needs to be mutable. This is difficult becauseRc enforcesmemory 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 thevalue we wish to mutate in aRefCell, which providesinteriormutability: a method to achieve mutability through a shared reference.RefCell enforces Rust’s borrowing rules at runtime.
usestd::rc::Rc;usestd::rc::Weak;usestd::cell::RefCell;structOwner { name: String, gadgets: RefCell<Vec<Weak<Gadget>>>,// ...other fields}structGadget { id: i32, owner: Rc<Owner>,// ...other fields}fnmain() {// Create a reference-counted `Owner`. Note that we've put the `Owner`'s // vector of `Gadget`s inside a `RefCell` so that we can mutate it through // a shared reference.letgadget_owner: Rc<Owner> = Rc::new( Owner { name:"Gadget Man".to_string(), gadgets: RefCell::new(vec![]), } );// Create `Gadget`s belonging to `gadget_owner`, as before.letgadget1 = Rc::new( Gadget { id:1, owner: Rc::clone(&gadget_owner), } );letgadget2 = Rc::new( Gadget { id:2, owner: Rc::clone(&gadget_owner), } );// Add the `Gadget`s to their `Owner`.{letmutgadgets = gadget_owner.gadgets.borrow_mut(); gadgets.push(Rc::downgrade(&gadget1)); gadgets.push(Rc::downgrade(&gadget2));// `RefCell` dynamic borrow ends here.}// Iterate over our `Gadget`s, printing their details out.forgadget_weakingadget_owner.gadgets.borrow().iter() {// `gadget_weak` is a `Weak<Gadget>`. Since `Weak` pointers can't // guarantee the allocation still exists, we need to call // `upgrade`, which returns an `Option<Rc<Gadget>>`. // // In this case we know the allocation still exists, so we simply // `unwrap` the `Option`. In a more complicated program, you might // need graceful error handling for a `None` result.letgadget = gadget_weak.upgrade().unwrap();println!("Gadget {} owned by {}", gadget.id, gadget.owner.name); }// At the end of the function, `gadget_owner`, `gadget1`, and `gadget2` // are destroyed. There are now no strong (`Rc`) pointers to the // gadgets, so they are destroyed. This zeroes the reference count on // Gadget Man, so he gets destroyed as well.}