Rc & Arc
Rc<T> reference-counts for single-threaded sharing. Arc<T> uses atomic refcount for thread-safe sharing.
Recipe
use std::sync::Arc;
use std::thread;
fn main() {
let data = Arc::new(vec![1, 2, 3]);
let d = Arc::clone(&data);
thread::spawn(move || println!("{:?}", d));
println!("{:?}", data);
}When to reach for this: Multiple owners of immutable data; Arc across threads.
Working Example
use std::rc::Rc;
struct Node { value: i32, next: Option<Rc<Node>> }
fn main() {
let tail = Rc::new(Node { value: 2, next: None });
let head = Rc::new(Node { value: 1, next: Some(Rc::clone(&tail)) });
println!("{}", head.value);
}What this demonstrates:
Rc::cloneincrements count, shallow clone- Immutable sharing of graph nodes
Option<Rc<Node>>for singly-linked structure
Deep Dive
Rc not Send. Arc is Send + Sync if T: Send + Sync. get_mut unique when strong_count==1.
Gotchas
- Rc across threads - Compile error. Fix:
Arc. - Arc + mutation - Need
Mutex/RwLockinside. Fix:Arc<Mutex<T>>. - Reference cycles leak - Rc cycles never drop. Fix:
Weak. - Clone confusion -
Rc::clonenot deep clone of inner. - Weak upgrade fails - Target dropped. Fix: Handle
None.
Alternatives
| Alternative | Use When | Don't Use When |
|---|---|---|
Borrow &T | Single owner lifetime | Multiple owners |
Arena + indices | Graphs without refcount | Simple share |
Cow | Mostly read | True shared ownership |
FAQs
strong_count?
Rc::strong_count(&a).weak_count?
Tracks Weak refs.try_unwrap?
If count 1, extract T.make_mut?
Clone inner if unique else mutate in place.Arc downgrade?
Arc::downgrade to Weak.serde Arc?
Serialize inner T.weak cycles?
Weak parent pointers break Rc cycles.performance?
Atomic inc/dec Arc cost vs Rc.no_std Arc?
portable-atomic ecosystems.when not Arc?
Single thread - Rc cheaper.Related
Stack versions: This page was written for Rust 1.97.0 (edition 2024), Tokio 1.x, Axum 0.8, serde 1.0, sqlx 0.8, clap 4, and Polars 0.46+.