You'll spend more time implementing standard-library traits than writing your own. A handful show up constantly — knowing them turns 'why won't this compile?' into 'oh, I need to derive that.'
The derivable big five
Debug (print with {:?}), Clone (explicit deep copy), Copy (implicit bitwise copy), PartialEq (the == operator), and Default (a ::default() value) can all be auto-generated with #[derive(...)]. Put them above a struct and the compiler writes the obvious implementation. You'll type #[derive(Debug, Clone, PartialEq)] on reflex.
Display vs Debug
Debug is for developers (derivable, {:?}); Display is for end users (you implement it by hand, {}). The split is deliberate: the messy internal view and the polished user-facing view are different jobs, so Rust makes them different traits.
From and Into: conversions
Implement From<A> for B and you get B::from(a) — and a.into() for free, because Into is auto-derived from From. This pair is everywhere: error conversions (the ? operator uses From to convert error types), type wrappers, ergonomic constructors. Implement From, never Into directly.
#[derive(...)] for the mechanical traits (Debug, Clone, PartialEq, Default). Hand-implement only the ones that need real logic — Display for human formatting, From for conversions, Iterator for custom iteration. Let the compiler write the boilerplate.This is the bridge to everything
From here on, the standard library is your playground, and it's all traits: Iterator powers the Collections track, From powers error handling, Send/Sync power concurrency. You now have the one concept — traits — that the rest of Rust is built from.