Quick Reference Card
Pattern Decision Guide
Need type safety for primitives?
āāā Newtype pattern (Ch3)
Need compile-time state enforcement?
āāā Type-state pattern (Ch3)
Need a "tag" with no runtime data?
āāā PhantomData (Ch4)
Need to break Rc/Arc reference cycles?
āāā Weak<T> / sync::Weak<T> (Ch8)
Need to wait for a condition without busy-looping?
āāā Condvar + Mutex (Ch6)
Need to handle "one of N types"?
āāā Known closed set ā Enum
āāā Open set, hot path ā Generics
āāā Open set, cold path ā dyn Trait
āāā Completely unknown types ā Any + TypeId (Ch2)
Need shared state across threads?
āāā Simple counter/flag ā Atomics
āāā Short critical section ā Mutex
āāā Read-heavy ā RwLock
āāā Lazy one-time init ā OnceLock / LazyLock (Ch6)
āāā Complex state ā Actor + Channels
Need to parallelize computation?
āāā Collection processing ā rayon::par_iter
āāā Background task ā thread::spawn
āāā Borrow local data ā thread::scope
Need async I/O or concurrent networking?
āāā Basic ā tokio + async/await (Ch15)
āāā Advanced (streams, middleware) ā see Async Rust Training
Need error handling?
āāā Library ā thiserror (#[derive(Error)])
āāā Application ā anyhow (Result<T>)
Need to prevent a value from being moved?
āāā Pin<T> (Ch8) ā required for Futures, self-referential types
Trait Bounds Cheat Sheet
| Bound | Meaning |
|---|---|
T: Clone | Can be duplicated |
T: Send | Can be moved to another thread |
T: Sync | &T can be shared between threads |
T: 'static | Contains no non-static references |
T: Sized | Size known at compile time (default) |
T: ?Sized | Size may not be known ([T], dyn Trait) |
T: Unpin | Safe to move after pinning |
T: Default | Has a default value |
T: Into<U> | Can be converted to U |
T: AsRef<U> | Can be borrowed as &U |
T: Deref<Target = U> | Auto-derefs to &U |
F: Fn(A) -> B | Callable, borrows state immutably |
F: FnMut(A) -> B | Callable, may mutate state |
F: FnOnce(A) -> B | Callable exactly once, may consume state |
Lifetime Elision Rules
The compiler inserts lifetimes automatically in three cases (so you don't have to):
// Rule 1: Each reference parameter gets its own lifetime
// fn foo(x: &str, y: &str) ā fn foo<'a, 'b>(x: &'a str, y: &'b str)
// Rule 2: If there's exactly ONE input lifetime, it's used for all outputs
// fn foo(x: &str) -> &str ā fn foo<'a>(x: &'a str) -> &'a str
// Rule 3: If one parameter is &self or &mut self, its lifetime is used
// fn foo(&self, x: &str) -> &str ā fn foo<'a>(&'a self, x: &str) -> &'a str
When you MUST write explicit lifetimes:
- Multiple input references and a reference output (compiler can't guess which input)
- Struct fields that hold references:
struct Ref<'a> { data: &'a str } 'staticbounds when you need data without borrowed references
Common Derive Traits
#[derive(
Debug, // {:?} formatting
Clone, // .clone()
Copy, // Implicit copy (only for simple types)
PartialEq, Eq, // == comparison
PartialOrd, Ord, // < > comparison + sorting
Hash, // HashMap/HashSet key
Default, // Type::default()
)]
struct MyType { /* ... */ }
Module Visibility Quick Reference
pub ā visible everywhere
pub(crate) ā visible within the crate
pub(super) ā visible to parent module
pub(in path) ā visible within a specific path
(nothing) ā private to current module + children
Further Reading
| Resource | Why |
|---|---|
| Rust Design Patterns | Catalog of idiomatic patterns and anti-patterns |
| Rust API Guidelines | Official checklist for polished public APIs |
| Rust Atomics and Locks | Mara Bos's deep dive into concurrency primitives |
| The Rustonomicon | Official guide to unsafe Rust and dark corners |
| Error Handling in Rust | Andrew Gallant's comprehensive guide |
| Jon Gjengset ā Crust of Rust series | Deep dives into iterators, lifetimes, channels, etc. |
| Effective Rust | 35 specific ways to improve your Rust code |
End of Rust Patterns & Engineering How-Tos