Lesson 57 of 94
Rc & Weak: Shared Ownership
Ownership says every value has exactly one owner. Sometimes that's not the right model: a configuration read by many services, a graph where several nodes point at the same node, a cache entry handed to many callers.
Rc<T> ("reference counted") supports this explicitly, for one value at a time. Cloning an Rc doesn't copy the value: it creates another owner and increments a counter. When the last Rc is dropped, the count reaches zero and the value is freed, immediately and deterministically.
| Concept | Rust |
|---|---|
| Another owner | let c = Rc::clone(&shared); |
| When the value is freed | The last Rc drop frees it immediately |
| Cycles | Cycles leak: break them with Weak |
| Non-owning reference | Weak<T> |
| Threads | Rc is single-threaded; use Arc across threads |
1. Several owners of one value
use std::rc::Rc;
fn main() {
let config = Rc::new(String::from("region=eu-west-1"));
let for_api = Rc::clone(&config);
let for_worker = Rc::clone(&config);
println!("{config} / {for_api} / {for_worker}");
println!("owners: {}", Rc::strong_count(&config));
}region=eu-west-1 / region=eu-west-1 / region=eu-west-1
owners: 3Rc::clone(&x) is the idiomatic spelling. x.clone() does the same thing, but writing Rc::clone makes it obvious to readers that this is a cheap counter increment, not a deep copy.
2. The value is freed when the last owner goes away
use std::rc::Rc;
struct Connection(&'static str);
impl Drop for Connection {
fn drop(&mut self) {
println!("closing {}", self.0);
}
}
fn main() {
let a = Rc::new(Connection("db"));
println!("count = {}", Rc::strong_count(&a));
{
let b = Rc::clone(&a);
println!("count = {} (b alive)", Rc::strong_count(&b));
}
println!("count = {} (b dropped)", Rc::strong_count(&a));
drop(a);
println!("after last owner dropped");
}count = 1
count = 2 (b alive)
count = 1 (b dropped)
closing db
after last owner dropped3. Cloning an Rc doesn't clone the value
use std::rc::Rc;
fn main() {
let big = Rc::new(vec![0_u8; 1_000_000]);
let copies: Vec<Rc<Vec<u8>>> = (0..1_000).map(|_| Rc::clone(&big)).collect();
println!("{} handles, one 1 MB buffer, count {}", copies.len(), Rc::strong_count(&big));
println!("same allocation: {}", Rc::ptr_eq(&big, &copies[999]));
}1000 handles, one 1 MB buffer, count 1001
same allocation: trueRc::ptr_eq checks whether two Rcs point to the same value.
4. Why not just use references?
A reference &T must not outlive its owner, and the compiler must be able to see that. When there's no single owner that clearly outlives everything else, use Rc.
use std::rc::Rc;
struct Service {
name: &'static str,
settings: Rc<Vec<(&'static str, &'static str)>>,
}
fn build_services() -> Vec<Service> {
let settings = Rc::new(vec![("timeout", "30s"), ("region", "eu")]);
vec![
Service { name: "api", settings: Rc::clone(&settings) },
Service { name: "worker", settings: Rc::clone(&settings) },
]
// `settings` (the local handle) is dropped here, but the data lives on in the services
}
fn main() {
let services = build_services();
for s in &services {
println!("{} sees {:?}", s.name, s.settings);
}
}api sees [("timeout", "30s"), ("region", "eu")]
worker sees [("timeout", "30s"), ("region", "eu")]With plain references, settings would have to be owned by something outside build_services that outlives both services.
5. Rc<T> only gives shared (read-only) access
Because several owners may hold the same value, Rc never hands out &mut T. Changing a value through an Rc needs interior mutability (RefCell, the next lesson), or copy-on-write (example 7).
use std::rc::Rc;
fn main() {
let shared = Rc::new(vec![1, 2, 3]);
let other = Rc::clone(&shared);
shared.push(4);
println!("{:?}", other);
}error[E0596]: cannot borrow data in an `Rc` as mutable
--> src/main.rs:6:5
|
6 | shared.push(4);
| ^^^^^^ cannot borrow as mutable
|
= help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc<Vec<i32>>`6. Rc<str> and Rc<[T]> for shared immutable data
A string or slice that many places read, and nobody changes, can be shared as Rc<str> or Rc<[T]>. Cloning is a counter increment instead of a string copy.
use std::rc::Rc;
fn main() {
let tenant: Rc<str> = Rc::from("acme-corp");
let events: Vec<(Rc<str>, &str)> = ["login", "upload", "logout"].iter().map(|e| (Rc::clone(&tenant), *e)).collect();
for (t, e) in &events {
println!("[{t}] {e}");
}
println!("one string, {} owners", Rc::strong_count(&tenant));
let primes: Rc<[u32]> = Rc::from(vec![2, 3, 5, 7]);
let alias = Rc::clone(&primes);
println!("{:?} {}", alias, alias.len());
}[acme-corp] login
[acme-corp] upload
[acme-corp] logout
one string, 4 owners
[2, 3, 5, 7] 47. Rc::make_mut: copy-on-write
make_mut gives a &mut T. If this Rc is the only owner, it changes the value in place. If there are other owners, it first clones the value so they keep seeing the old one.
use std::rc::Rc;
fn main() {
let original = Rc::new(vec!["a", "b"]);
let mut edited = Rc::clone(&original);
Rc::make_mut(&mut edited).push("c"); // shared: clones first
println!("original {:?}, edited {:?}", original, edited);
println!("shared now? {}", Rc::ptr_eq(&original, &edited));
Rc::make_mut(&mut edited).push("d"); // edited is the only owner of its copy: no clone
println!("edited {:?}, count {}", edited, Rc::strong_count(&edited));
}original ["a", "b"], edited ["a", "b", "c"]
shared now? false
edited ["a", "b", "c", "d"], count 1Copy-on-write makes snapshots cheap: share freely, and pay for a copy only when someone actually changes the data.
8. Getting the value back with try_unwrap
Rc::try_unwrap returns the inner value if this is the last owner, or gives the Rc back otherwise.
use std::rc::Rc;
fn main() {
let report = Rc::new(String::from("final report"));
let viewer = Rc::clone(&report);
let report = match Rc::try_unwrap(report) {
Ok(s) => panic!("unexpected sole owner: {s}"),
Err(still_shared) => still_shared,
};
drop(viewer);
let owned: String = Rc::try_unwrap(report).expect("viewer dropped, so we are the only owner");
println!("got owned String: {owned}");
}got owned String: final reportRc::unwrap_or_clone(rc) is the shortcut: it returns the value, cloning it only if needed.
9. Shared nodes in a graph
Several nodes can point to the same child. With Box, a child could only have one parent.
use std::rc::Rc;
#[derive(Debug)]
struct Module {
name: &'static str,
deps: Vec<Rc<Module>>,
}
fn main() {
let logging = Rc::new(Module { name: "logging", deps: vec![] });
let http = Rc::new(Module { name: "http", deps: vec![Rc::clone(&logging)] });
let db = Rc::new(Module { name: "db", deps: vec![Rc::clone(&logging)] });
let app = Module { name: "app", deps: vec![Rc::clone(&http), Rc::clone(&db)] };
for d in &app.deps {
let names: Vec<&str> = d.deps.iter().map(|m| m.name).collect();
println!("{} -> {} -> {:?}", app.name, d.name, names);
}
println!("logging is shared by {} owners", Rc::strong_count(&logging));
}app -> http -> ["logging"]
app -> db -> ["logging"]
logging is shared by 3 owners10. Rc is not thread-safe
Rc uses a plain counter, which would be corrupted by two threads updating it at once. The compiler refuses to send an Rc to another thread. Use Arc ("atomically reference counted") there instead; it has the same API. See Shared State.
use std::rc::Rc;
use std::thread;
fn main() {
let data = Rc::new(vec![1, 2, 3]);
let handle = thread::spawn(move || println!("{:?}", data));
handle.join().unwrap();
}error[E0277]: `Rc<Vec<i32>>` cannot be sent between threads safely
--> src/main.rs:6:32
|
6 | let handle = thread::spawn(move || println!("{:?}", data));
| ------------- -------^^^^^^^^^^^^^^^^^^^^^^^
| | |
| | `Rc<Vec<i32>>` cannot be sent between threads safely
| | within this `{closure@src/main.rs:6:32: 6:39}`
| required by a bound introduced by this call
|
= help: within `{closure@src/main.rs:6:32: 6:39}`, the trait `Send` is not implemented for `Rc<Vec<i32>>`
note: required because it's used within this closure
--> src/main.rs:6:32
|
6 | let handle = thread::spawn(move || println!("{:?}", data));
| ^^^^^^^
note: required by a bound in `spawn`
--> /rustc/<version>/library/std/src/thread/functions.rs:125:0use std::sync::Arc;
use std::thread;
fn main() {
let data = Arc::new(vec![1, 2, 3]);
let worker_copy = Arc::clone(&data);
let handle = thread::spawn(move || worker_copy.iter().sum::<i32>());
println!("sum from thread: {}, owners after join: {}", handle.join().unwrap(), Arc::strong_count(&data));
}sum from thread: 6, owners after join: 1Rc is slightly faster because it avoids atomic operations, which is why both exist.
11. Reference cycles leak memory
If a holds an Rc to b and b holds an Rc to a, neither count ever reaches zero, so neither is freed. (Building a cycle requires mutation through an Rc, so this example uses RefCell, from the next lesson.)
use std::cell::RefCell;
use std::rc::Rc;
struct Node {
name: &'static str,
other: RefCell<Option<Rc<Node>>>,
}
impl Drop for Node {
fn drop(&mut self) {
println!("dropping {}", self.name);
}
}
fn main() {
{
let a = Rc::new(Node { name: "a", other: RefCell::new(None) });
let b = Rc::new(Node { name: "b", other: RefCell::new(Some(Rc::clone(&a))) });
*a.other.borrow_mut() = Some(Rc::clone(&b)); // a -> b -> a: a cycle
println!("a count {}, b count {}", Rc::strong_count(&a), Rc::strong_count(&b));
}
println!("end of scope: nothing was dropped, the cycle leaked");
}a count 2, b count 2
end of scope: nothing was dropped, the cycle leaked12. Weak<T>: a reference that doesn't keep the value alive
A Weak points to an Rc's value without counting as an owner. To use it, call upgrade(), which returns Some(Rc<T>) if the value still exists or None if it was dropped.
use std::rc::{Rc, Weak};
fn main() {
let session = Rc::new(String::from("session-42"));
let observer: Weak<String> = Rc::downgrade(&session);
println!("strong {}, weak {}", Rc::strong_count(&session), Rc::weak_count(&session));
println!("upgrade while alive: {:?}", observer.upgrade());
drop(session);
println!("upgrade after drop: {:?}", observer.upgrade());
}strong 1, weak 1
upgrade while alive: Some("session-42")
upgrade after drop: None13. Parent pointers with Weak
The classic use of Weak: children own nothing of their parent, so parent ↔ child links don't form a cycle. Parents own children with Rc; children refer to parents with Weak.
use std::cell::RefCell;
use std::rc::{Rc, Weak};
struct Dept {
name: &'static str,
parent: RefCell<Weak<Dept>>,
children: RefCell<Vec<Rc<Dept>>>,
}
impl Dept {
fn new(name: &'static str) -> Rc<Dept> {
Rc::new(Dept { name, parent: RefCell::new(Weak::new()), children: RefCell::new(Vec::new()) })
}
fn add_child(parent: &Rc<Dept>, child: Rc<Dept>) {
*child.parent.borrow_mut() = Rc::downgrade(parent);
parent.children.borrow_mut().push(child);
}
fn path(&self) -> String {
match self.parent.borrow().upgrade() {
Some(p) => format!("{} / {}", p.path(), self.name),
None => self.name.to_string(),
}
}
}
fn main() {
let company = Dept::new("Acme");
let eng = Dept::new("Engineering");
let platform = Dept::new("Platform");
Dept::add_child(&company, Rc::clone(&eng));
Dept::add_child(&eng, Rc::clone(&platform));
println!("{}", platform.path());
println!("Acme has {} child(ren); Engineering strong count {}", company.children.borrow().len(), Rc::strong_count(&eng));
}Acme / Engineering / Platform
Acme has 1 child(ren); Engineering strong count 214. Dropping the root frees the whole tree
Because children only hold Weak references upward, dropping the owners frees everything, with no leak.
use std::cell::RefCell;
use std::rc::{Rc, Weak};
struct Node {
name: &'static str,
parent: RefCell<Weak<Node>>,
children: RefCell<Vec<Rc<Node>>>,
}
impl Drop for Node {
fn drop(&mut self) {
println!("freed {}", self.name);
}
}
fn main() {
let leaf_handle;
{
let root = Rc::new(Node { name: "root", parent: RefCell::new(Weak::new()), children: RefCell::new(vec![]) });
let leaf = Rc::new(Node { name: "leaf", parent: RefCell::new(Rc::downgrade(&root)), children: RefCell::new(vec![]) });
root.children.borrow_mut().push(Rc::clone(&leaf));
leaf_handle = Rc::downgrade(&leaf);
println!("leaf's parent: {:?}", leaf.parent.borrow().upgrade().map(|p| p.name));
}
println!("leaf still alive? {}", leaf_handle.upgrade().is_some());
}leaf's parent: Some("root")
freed root
freed leaf
leaf still alive? false15. A weak cache: don't keep things alive just because they're cached
A cache holding Weak references returns an object while someone is still using it, but doesn't prevent it from being freed.
use std::collections::HashMap;
use std::rc::{Rc, Weak};
struct TextureCache {
entries: HashMap<&'static str, Weak<Vec<u8>>>,
loads: u32,
}
impl TextureCache {
fn get(&mut self, name: &'static str) -> Rc<Vec<u8>> {
if let Some(tex) = self.entries.get(name).and_then(Weak::upgrade) {
return tex;
}
self.loads += 1;
let tex = Rc::new(vec![self.loads as u8; 4]); // pretend this is loaded from disk
self.entries.insert(name, Rc::downgrade(&tex));
tex
}
}
fn main() {
let mut cache = TextureCache { entries: HashMap::new(), loads: 0 };
let a = cache.get("grass.png");
let b = cache.get("grass.png"); // reused: `a` keeps it alive
println!("same texture: {}, loads {}", Rc::ptr_eq(&a, &b), cache.loads);
drop(a);
drop(b);
let c = cache.get("grass.png"); // everyone dropped it, so it's reloaded
println!("reloaded: {:?}, loads {}", c, cache.loads);
}same texture: true, loads 1
reloaded: [2, 2, 2, 2], loads 216. Counting owners for diagnostics
strong_count and weak_count are handy for tests and debugging, like inspecting reference counts in a heap dump.
use std::rc::Rc;
fn main() {
let theme = Rc::new("dark");
let widgets: Vec<Rc<&str>> = (0..5).map(|_| Rc::clone(&theme)).collect();
let weak_listeners: Vec<_> = (0..2).map(|_| Rc::downgrade(&theme)).collect();
println!("strong {}, weak {}", Rc::strong_count(&theme), Rc::weak_count(&theme));
drop(widgets);
println!("strong {}, weak {}", Rc::strong_count(&theme), Rc::weak_count(&theme));
println!("listeners can still see it: {}", weak_listeners.iter().all(|w| w.upgrade().is_some()));
}strong 6, weak 2
strong 1, weak 2
listeners can still see it: true17. Rc in function signatures
Take &T when a function only reads the value; take Rc<T> only when it needs to keep a share for later.
use std::rc::Rc;
struct Logger {
prefix: Rc<str>,
}
fn print_prefix(prefix: &str) {
println!("prefix is {prefix}"); // only reads: borrow
}
fn make_logger(prefix: &Rc<str>) -> Logger {
Logger { prefix: Rc::clone(prefix) } // keeps a share: clone the Rc
}
fn main() {
let app_name: Rc<str> = Rc::from("checkout");
print_prefix(&app_name);
let l1 = make_logger(&app_name);
let l2 = make_logger(&app_name);
println!("{} {} owners={}", l1.prefix, l2.prefix, Rc::strong_count(&app_name));
}prefix is checkout
checkout checkout owners=318. Realistic example: an immutable, shareable document history
Each version shares unchanged paragraphs with the previous version, so keeping 100 versions doesn't mean 100 full copies.
use std::rc::Rc;
#[derive(Clone)]
struct Version {
paragraphs: Vec<Rc<String>>,
}
impl Version {
fn edit(&self, index: usize, text: &str) -> Version {
let mut paragraphs = self.paragraphs.clone(); // clones the Rc handles, not the text
paragraphs[index] = Rc::new(text.to_string());
Version { paragraphs }
}
}
fn main() {
let v1 = Version { paragraphs: vec![Rc::new(String::from("Intro")), Rc::new(String::from("Body")), Rc::new(String::from("Conclusion"))] };
let v2 = v1.edit(1, "Better body");
let v3 = v2.edit(2, "Better conclusion");
for (i, v) in [&v1, &v2, &v3].iter().enumerate() {
let texts: Vec<&str> = v.paragraphs.iter().map(|p| p.as_str()).collect();
println!("v{}: {:?}", i + 1, texts);
}
println!("'Intro' shared by all 3 versions: {}", Rc::strong_count(&v1.paragraphs[0]) == 3);
}v1: ["Intro", "Body", "Conclusion"]
v2: ["Intro", "Better body", "Conclusion"]
v3: ["Intro", "Better body", "Better conclusion"]
'Intro' shared by all 3 versions: trueThis structural sharing is how persistent (immutable) data structures work in functional languages and in editors' undo systems.
19. Realistic example: an observer that doesn't keep subjects alive
Listeners register with a Weak reference, so a dropped listener is skipped (and cleaned up) instead of being kept alive forever.
use std::cell::RefCell;
use std::rc::{Rc, Weak};
struct Listener {
name: &'static str,
received: RefCell<Vec<String>>,
}
struct EventBus {
listeners: Vec<Weak<Listener>>,
}
impl EventBus {
fn publish(&mut self, event: &str) {
self.listeners.retain(|w| w.upgrade().is_some()); // forget dropped listeners
for w in &self.listeners {
if let Some(l) = w.upgrade() {
l.received.borrow_mut().push(event.to_string());
}
}
}
}
fn main() {
let mut bus = EventBus { listeners: Vec::new() };
let dashboard = Rc::new(Listener { name: "dashboard", received: RefCell::new(vec![]) });
let popup = Rc::new(Listener { name: "popup", received: RefCell::new(vec![]) });
bus.listeners.push(Rc::downgrade(&dashboard));
bus.listeners.push(Rc::downgrade(&popup));
bus.publish("price changed");
drop(popup); // the popup window was closed
bus.publish("order filled");
println!("{} got {:?}", dashboard.name, dashboard.received.borrow());
println!("bus now tracks {} listener(s)", bus.listeners.len());
}dashboard got ["price changed", "order filled"]
bus now tracks 1 listener(s)20. Realistic example: a shared read-only catalog
Many carts reference the same product records. Rc<Product> avoids copying product data into every cart line.
use std::collections::HashMap;
use std::rc::Rc;
#[derive(Debug)]
struct Product {
sku: &'static str,
name: &'static str,
price_cents: u64,
}
struct Cart {
lines: Vec<(Rc<Product>, u32)>,
}
impl Cart {
fn total(&self) -> u64 {
self.lines.iter().map(|(p, q)| p.price_cents * *q as u64).sum()
}
}
fn main() {
let catalog: HashMap<&str, Rc<Product>> = [
Product { sku: "KB-1", name: "Keyboard", price_cents: 12_900 },
Product { sku: "MS-2", name: "Mouse", price_cents: 3_900 },
]
.into_iter()
.map(|p| (p.sku, Rc::new(p)))
.collect();
let cart_a = Cart { lines: vec![(Rc::clone(&catalog["KB-1"]), 1), (Rc::clone(&catalog["MS-2"]), 2)] };
let cart_b = Cart { lines: vec![(Rc::clone(&catalog["MS-2"]), 1)] };
println!("cart A {} cents, cart B {} cents", cart_a.total(), cart_b.total());
println!("{} is referenced by {} owners", catalog["MS-2"].name, Rc::strong_count(&catalog["MS-2"]));
}cart A 20700 cents, cart B 3900 cents
Mouse is referenced by 3 owners21. Realistic example: a doubly linked list with Weak back pointers
Forward links own the next node (Rc); backward links don't (Weak), so there's no cycle.
use std::cell::RefCell;
use std::rc::{Rc, Weak};
struct Node {
value: i32,
next: RefCell<Option<Rc<Node>>>,
prev: RefCell<Weak<Node>>,
}
fn build(values: &[i32]) -> Option<Rc<Node>> {
let mut head: Option<Rc<Node>> = None;
let mut tail: Option<Rc<Node>> = None;
for &v in values {
let node = Rc::new(Node { value: v, next: RefCell::new(None), prev: RefCell::new(Weak::new()) });
match &tail {
Some(t) => {
*node.prev.borrow_mut() = Rc::downgrade(t);
*t.next.borrow_mut() = Some(Rc::clone(&node));
}
None => head = Some(Rc::clone(&node)),
}
tail = Some(node);
}
head
}
fn main() {
let head = build(&[1, 2, 3, 4]).unwrap();
let mut forward = Vec::new();
let mut current = Some(Rc::clone(&head));
let mut last = None;
while let Some(node) = current {
forward.push(node.value);
current = node.next.borrow().clone();
last = Some(node);
}
let mut backward = Vec::new();
let mut current = last;
while let Some(node) = current {
backward.push(node.value);
current = node.prev.borrow().upgrade();
}
println!("forward {:?}, backward {:?}", forward, backward);
}forward [1, 2, 3, 4], backward [4, 3, 2, 1]In real code, use VecDeque or std::collections::LinkedList; this shows how Rc/Weak structures are built.
22. Realistic example: an interned string pool
Repeated strings (tag names, event types) are stored once and shared as Rc<str>, cutting memory for large datasets.
use std::collections::HashSet;
use std::rc::Rc;
struct Interner {
pool: HashSet<Rc<str>>,
}
impl Interner {
fn intern(&mut self, s: &str) -> Rc<str> {
if let Some(existing) = self.pool.get(s) {
return Rc::clone(existing);
}
let new: Rc<str> = Rc::from(s);
self.pool.insert(Rc::clone(&new));
new
}
}
fn main() {
let mut interner = Interner { pool: HashSet::new() };
let raw_events = ["click", "view", "click", "click", "purchase", "view"];
let events: Vec<Rc<str>> = raw_events.iter().map(|e| interner.intern(e)).collect();
println!("{} events, {} distinct strings stored", events.len(), interner.pool.len());
println!("'click' shared by {} handles", Rc::strong_count(&events[0]));
}6 events, 3 distinct strings stored
'click' shared by 4 handlesHashSet<Rc<str>> can be looked up with a &str because Rc<str> borrows as str, the same mechanism that lets HashMap<String, V> be queried with &str.
23. Realistic example: undo snapshots with make_mut
The editor keeps snapshots as Rcs. Taking a snapshot is a counter increment; the next edit triggers one real copy, and only if a snapshot is still sharing the data.
use std::rc::Rc;
struct Editor {
doc: Rc<Vec<String>>,
history: Vec<Rc<Vec<String>>>,
}
impl Editor {
fn snapshot(&mut self) {
self.history.push(Rc::clone(&self.doc));
}
fn append(&mut self, line: &str) {
let copied = Rc::strong_count(&self.doc) > 1;
Rc::make_mut(&mut self.doc).push(line.to_string());
println!("append {line:?} (copied: {copied})");
}
fn undo(&mut self) {
if let Some(prev) = self.history.pop() {
self.doc = prev;
}
}
}
fn main() {
let mut e = Editor { doc: Rc::new(Vec::new()), history: Vec::new() };
e.append("line 1");
e.snapshot();
e.append("line 2");
e.append("line 3");
println!("{:?}", e.doc);
e.undo();
println!("after undo {:?}", e.doc);
}append "line 1" (copied: false)
append "line 2" (copied: true)
append "line 3" (copied: false)
["line 1", "line 2", "line 3"]
after undo ["line 1"]24. Rc vs Box vs references
| You need | Use |
|---|---|
| One owner, value on the heap | Box<T> |
| Temporary access, clear owner that outlives the user | &T / &mut T |
| Several owners, single thread, read-only | Rc<T> |
| Several owners, single thread, mutable | Rc<RefCell<T>> (next lesson) |
| Several owners across threads | Arc<T> / Arc<Mutex<T>> (Shared State) |
| A non-owning back pointer or cache entry | Weak<T> |
use std::rc::Rc;
fn main() {
let boxed = Box::new(1);
let shared = Rc::new(1);
let shared2 = Rc::clone(&shared);
let borrowed = &*boxed;
println!("{boxed} {shared} {shared2} {borrowed} (Rc owners: {})", Rc::strong_count(&shared));
}1 1 1 1 (Rc owners: 2)Summary
Rc<T>lets several owners share one value.Rc::cloneincrements a count; the value is freed when the last owner is dropped.Rconly gives shared access. UseRc::make_mutfor copy-on-write, orRefCellfor shared mutation.Rc::ptr_eqcompares identity;strong_countandweak_countreport owners.Rccycles leak memory. UseWeakfor parent pointers, back links, observers, and caches, andupgrade()to use aWeak.Rcis single-threaded.Arcis its thread-safe equivalent.
Next: Cell & RefCell.
