#[derive(...)]
#[derive(Trait1, Trait2, ...)] is an outer attribute applied to a struct, enum, or union that instructs the compiler (or a procedural derive macro) to automatically generate impl Trait for Type blocks by inspecting the type's fields or variants. Crucially, #[derive(...)] generates an implementation that does not alter the original struct or enum definition—it appends standalone impl blocks alongside it.
Built-In Standard Library Derive Macros
| Derive Macro | Trait Implemented | Generated Behavior |
|---|---|---|
Debug |
std::fmt::Debug |
Formats struct/enum name and all fields for {:?} and {:#?} |
Clone |
std::clone::Clone |
Calls .clone() on every field or active enum variant |
Copy |
std::marker::Copy |
Opts into bitwise copy semantics (requires Clone and all fields : Copy) |
PartialEq |
std::cmp::PartialEq |
Compares all fields (or variant discriminants + payloads) with == in declaration order |
Eq |
std::cmp::Eq |
Marker asserting reflexive total equality (requires PartialEq and all fields : Eq) |
PartialOrd |
std::cmp::PartialOrd |
Lexicographical comparison of fields (or variants) from top to bottom |
Ord |
std::cmp::Ord |
Total lexicographical ordering (requires Eq + PartialOrd) |
Hash |
std::hash::Hash |
Feeds discriminant and all fields into Hasher in declaration order |
Default |
std::default::Default |
Calls Default::default() on each struct field, or selects the #[default] enum variant |
Deriving Default on Enums with #[default]
Stabilized in Rust 1.62, #[derive(Default)] can be applied to an enum by marking one unit variant (a variant with no fields) with the helper attribute #[default]:
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
enum Priority {
Low,
#[default]
Normal,
High,
Critical,
}
#[derive(Debug, Default, PartialEq, Eq)]
struct Task {
name: String,
priority: Priority,
retries: u8,
}
fn main() {
let default_task = Task::default();
println!("default_task: {:?}", default_task);
// Lexicographical `Ord` on `Priority` follows variant declaration order:
println!("Low < Normal < Critical: {}", Priority::Low < Priority::Normal && Priority::Normal < Priority::Critical);
}
default_task: Task { name: "", priority: Normal, retries: 0 }
Low < Normal < Critical: true
The Generic Bound Limitation of #[derive(...)]
When #[derive(Clone)] or #[derive(Default)] is applied to a generic type struct Wrapper<T>, the built-in derive macro conservatively generates the bound where T: Clone or where T: Default on the impl block—even if T only appears inside PhantomData<T>, Rc<T>, Arc<T>, or a function pointer fn(T) that does not actually require T to implement the trait!
What `#[derive(Clone)]` Generates on `struct Handle<T>(Arc<T>)`:
impl<T: Clone> Clone for Handle<T> { ... } // <-- Unnecessarily requires `T: Clone`!
Manual `impl` (Works for ALL `T`, even when `T: !Clone`):
impl<T> Clone for Handle<T> {
fn clone(&self) -> Self { Self(Arc::clone(&self.0)) }
}
use std::sync::Arc;
struct NonCloneResource {
id: u32,
}
// If we used `#[derive(Clone)]`, `SharedHandle<NonCloneResource>::clone()`
// would fail to compile because `NonCloneResource` does not implement `Clone`!
struct SharedHandle<T> {
inner: Arc<T>,
}
impl<T> Clone for SharedHandle<T> {
fn clone(&self) -> Self {
Self {
inner: Arc::clone(&self.inner),
}
}
}
fn main() {
let h1 = SharedHandle {
inner: Arc::new(NonCloneResource { id: 99 }),
};
let h2 = h1.clone();
println!("cloned handle id = {}", h2.inner.id);
}
cloned handle id = 99