Rust Learning Path — Chapter 19. Rust references are usually the simplest way to access data, but some ownership patterns need more. Smart pointers combine pointer-like behavior with metadata and ownership rules. This chapter explains Box, Rc, Arc, RefCell, Deref, Drop, and common combinations.
1. What makes a pointer “smart”?
Types such as String and Vec already behave like smart pointers: they own heap data and manage cleanup. The standard smart-pointer types give you more explicit control over ownership patterns.
2. Box: single ownership on the heap
fn main() { let value = Box::new(42); println!("{}", value); }A Box owns its value and frees it when the box goes out of scope.
3. Recursive data structures
A recursive type needs an indirection because the compiler must know its size:
enum List { Cons(i32, Box<List>), Nil, }4. Rc: multiple owners in one thread
use std::rc::Rc; fn main() { let shared = Rc::new(String::from("config")); let a = Rc::clone(&shared); let b = Rc::clone(&shared); println!("owners = {}", Rc::strong_count(&shared)); println!("{a} {b}"); }Rc uses reference counting and is intended for single-threaded shared ownership.
5. Arc: thread-safe reference counting
Arc is the atomic, thread-safe counterpart to Rc:
use std::{sync::Arc, thread}; fn main() { let value = Arc::new(String::from("shared")); let other = Arc::clone(&value); thread::spawn(move || println!("{other}")) .join() .unwrap(); }Arc gives shared ownership; it does not automatically make the inner value mutable.
6. RefCell and interior mutability
RefCell moves borrow checking from compile time to runtime for a single-threaded value:
use std::cell::RefCell; fn main() { let retries = RefCell::new(3); *retries.borrow_mut() += 1; println!("{}", retries.borrow()); }If you violate the borrowing rules at runtime, RefCell panics. Use it intentionally, not as a shortcut around design problems.
7. Rc
A common single-thread pattern combines shared ownership with controlled mutation:
use std::{cell::RefCell, rc::Rc}; fn main() { let counter = Rc::new(RefCell::new(0)); let second = Rc::clone(&counter); *second.borrow_mut() += 1; println!("{}", counter.borrow()); }8. Arc
For shared mutable state across threads, Arc is a standard pattern:
use std::sync::{Arc, Mutex}; let state = Arc::new(Mutex::new(0)); let clone = Arc::clone(&state); std::thread::spawn(move || { let mut value = clone.lock().unwrap(); *value += 1; }).join().unwrap();Concurrency patterns are covered in depth in Chapter 21.
9. Deref
The Deref trait lets smart pointers behave like references in many contexts. This enables deref coercion, such as passing &String where &str is expected.
10. Drop
Drop runs cleanup when a value leaves scope:
struct Connection; impl Drop for Connection { fn drop(&mut self) { println!("connection released"); } }You generally do not call drop() as a method. To release early, use std::mem::drop(value).
11. Reference cycles
Two Rc values can form a cycle and prevent their strong counts from reaching zero. Use Weak for non-owning links such as parent pointers.
12. Which type should you choose?
| Need | Typical choice |
|---|---|
| Heap allocation with one owner | Box |
| Multiple owners, one thread | Rc |
| Multiple owners, many threads | Arc |
| Runtime-checked mutation, one thread | RefCell |
| Shared mutable state across threads | Arc |
13. Common mistakes
- Using Rc across threads.
- Using RefCell everywhere to silence borrow-checker design issues.
- Creating reference cycles.
- Adding Arc when ownership could stay simple and local.
- Holding a mutex guard longer than necessary.
Mini lab
Create an in-memory application state containing a request counter. First implement it with Rc for a single-threaded simulation, then convert it to Arc and increment it from multiple threads.
Key takeaways
Smart pointers solve specific ownership problems. Prefer ordinary ownership and references first; reach for Box, Rc, Arc or interior mutability when the data model truly requires them.
Join the discussion
0 CommentsAsk questions, add context, or share what worked.
More from Melochip Editorial
Learn what Playwright testing is, why modern QA teams use it, how testers can get started, and the major types...
7 min read · Sep 19, 2026
Learn how Kubernetes Deployments and ReplicaSets work with practical YAML, scaling, self-healing, rolling upda...
7 min read · Sep 17, 2026
Learn Kubernetes security best practices with RBAC, Secrets, ServiceAccounts, Pod securityContext, NetworkPoli...
6 min read · Sep 17, 2026Related articles
Learn Linux from the ground up with simple explanations of the kernel, distributions, filesystem, commands, pe...
4 min read · Updated Oct 1, 2026
Learn Kubernetes security best practices with RBAC, Secrets, ServiceAccounts, Pod securityContext, NetworkPoli...
6 min read · Sep 17, 2026
Learn how Kubernetes Deployments and ReplicaSets work with practical YAML, scaling, self-healing, rolling upda...
7 min read · Sep 17, 2026
Learn Kubernetes monitoring and logs with kubectl logs, events, metrics-server, top commands, Prometheus, Graf...
5 min read · Sep 17, 2026Stay in the loop. Get new Melochip articles
Receive Melochip article updates when new articles are available. Explicit opt-in only.
No comments yet. Start the discussion.