Traits & Generics Best Practices
How to Use This List
- Apply when designing public library traits and generic bounds.
- Review before adding
dyn Traitor blanket impls.
A - Trait Design
- Keep traits focused (single responsibility). Split read/write traits when needed.
- Prefer associated types for one output per impl. Avoid redundant generic params.
- Document object safety and
Send/Syncexpectations. Consumers need bounds clarity. - Seal traits not meant for external impl.
pub traitin private mod pattern. - Use default methods for shared logic. Reduce impl boilerplate.
B - Generics and Bounds
- Prefer
whereclauses for complex bounds. Readable signatures. - Use
impl Traitin params for simple single bounds. Less noise. - Default to static dispatch in hot paths. Profile before
dyn. - Avoid type complexity lint triggers. Type aliases for long bounds.
- Monomorphization awareness for binary size. Type erasure at edges.
C - Coherence and Orphans
- Newtype to impl local traits on foreign types. Orphan rule compliance.
- Avoid overlapping blanket impls. Coherence conflicts are painful.
- Semver blanket impl changes carefully. May break downstream impls.
- Extension traits in separate modules. Clear API surface.
- Test orphan patterns in CI for libraries. Prevent accidental conflicts.
D - Ergonomics
- Provide
From/Into/Defaultwhen natural. Idiomatic constructors. - Implement
Debugon public types. Supportability. - Use
Displayfor user-facing strings, notDebug. Log quality. - Prefer
AsRef/Borrowat boundaries for strings/paths. Flexible inputs. - Document trait contract (laws) in docs. e.g.
Eqreflexivity,Ordtransitivity.
FAQs
Trait vs inherent method?
Trait for polymorphism/shared contract; inherent for type-specific.How many traits per type?
As needed - avoid god traits.dyn in public API?
OK at plugin boundary; document `Send` needs.GAT when?
Lending iterators and streaming patterns.async trait?
Use native async fn in traits per edition docs.Testing traits?
Mock types implementing trait in tests.Object safety quick check?
No `Self` return, no generic methods on trait.Trait aliases?
Simplify bound groups: `trait SerializeMap = ...`.no_std traits?
`core` mirrors many `std` traits.Next?
Error handling with `Result` and `?`.Related
- Traits Basics
- Trait Objects & Dynamic Dispatch
- Blanket & Conditional Impls
- Architecture Trait-Based Abstraction
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+.