šŸ¦€/🧩/Summary and Reference Card

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

BoundMeaning
T: CloneCan be duplicated
T: SendCan be moved to another thread
T: Sync&T can be shared between threads
T: 'staticContains no non-static references
T: SizedSize known at compile time (default)
T: ?SizedSize may not be known ([T], dyn Trait)
T: UnpinSafe to move after pinning
T: DefaultHas 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) -> BCallable, borrows state immutably
F: FnMut(A) -> BCallable, may mutate state
F: FnOnce(A) -> BCallable 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 }
  • 'static bounds 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

ResourceWhy
Rust Design PatternsCatalog of idiomatic patterns and anti-patterns
Rust API GuidelinesOfficial checklist for polished public APIs
Rust Atomics and LocksMara Bos's deep dive into concurrency primitives
The RustonomiconOfficial guide to unsafe Rust and dark corners
Error Handling in RustAndrew Gallant's comprehensive guide
Jon Gjengset — Crust of Rust seriesDeep dives into iterators, lifetimes, channels, etc.
Effective Rust35 specific ways to improve your Rust code

End of Rust Patterns & Engineering How-Tos