Derivable Traits
A derivable trait is a trait that the compiler can implement automatically for a struct or enum when annotated with the #[derive(...)] attribute, generating field-by-field or variant-by-variant boilerplate at compile time.
Standard Library Derivable Traits
The standard library provides built-in derive macros for the following traits:
| Trait | Generated Implementation Behavior | Prerequisite Bounds on Fields |
|---|---|---|
Debug |
Formats type name and all fields/variants with {:?} and {:#?} |
All fields must implement Debug |
Clone |
Calls .clone() on every field to produce a deep duplicate |
All fields must implement Clone |
Copy |
Marks the type as trivially bitwise-copyable (memcpy) |
All fields must implement Copy, and Clone must also be implemented |
PartialEq |
Returns true for a == b iff every field/variant is equal (&&) |
All fields must implement PartialEq |
Eq |
Marker asserting that PartialEq is reflexive (a == a is always true) |
Type must implement PartialEq; all fields must implement Eq |
PartialOrd |
Compares fields lexicographically in declaration order | Type must implement PartialEq; all fields must implement PartialOrd |
Ord |
Total lexicographical ordering via .cmp() |
Type must implement Eq + PartialOrd; all fields must implement Ord |
Hash |
Feeds the discriminant (for enums) and every field into Hasher |
All fields must implement Hash |
Default |
Calls Default::default() on every struct field, or marks an enum variant with #[default] |
All fields must implement Default (or enum has one #[default] unit variant) |
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
struct Version {
major: u16,
minor: u16,
patch: u16,
}
fn main() {
let v0 = Version::default();
let v1 = Version {
major: 1,
minor: 2,
patch: 0,
};
let v2 = Version {
major: 1,
minor: 10,
patch: 0,
};
// Uses Debug, Ord (<), and Copy:
println!("Default: {v0:?}");
println!("{v1:?} < {v2:?} is {}", v1 < v2);
}
Default: Version { major: 0, minor: 0, patch: 0 }
Version { major: 1, minor: 2, patch: 0 } < Version { major: 1, minor: 10, patch: 0 } is true
Deriving Default and PartialOrd on Enums
For enums:
#[derive(PartialOrd, Ord)]orders variants from top to bottom in the order they are declared in theenumblock.#[derive(Default)](stabilized in Rust 1.62) requires placing the#[default]attribute on the unit variant that should act as the default:
#[derive(Debug, Default, PartialEq, Eq, PartialOrd, Ord)]
enum Priority {
Low,
#[default]
Normal,
High,
Critical,
}
fn main() {
let default_prio = Priority::default();
println!("Default priority: {default_prio:?}");
println!("Low < Critical: {}", Priority::Low < Priority::Critical);
}
Default priority: Normal
Low < Critical: true
When All Fields Must Satisfy the Derived Trait (E0204 / E0277)
If any field of a struct or enum does not implement the trait listed in #[derive(...)], compilation fails. For example, deriving Copy on a struct containing a heap-allocated String fails with E0204:
// ❌ does not compile
#[derive(Clone, Copy)]
struct UserLabel {
id: u32,
name: String,
}
fn main() {}
error[E0204]: the trait `Copy` cannot be implemented for this type
--> src/main.rs:2:17
|
2 | #[derive(Clone, Copy)]
| ^^^^
...
5 | name: String,
| ------------ this field does not implement `Copy`
Limitation of #[derive(...)] on Generic Wrapper Types
When you write #[derive(Clone)] struct Handle<T>(*const T); or struct Callback<T>(fn(T));, the built-in #[derive(Clone)] macro conservatively adds a where T: Clone bound to the generated impl<T: Clone> Clone for Callback<T>, even though fn(T) is always Copy and Clone regardless of whether T implements Clone.
In cases where a generic type parameter is only held inside a function pointer, raw pointer, or PhantomData<T>, write a manual impl<T> Clone for Callback<T> without the T: Clone bound instead of using #[derive(Clone)].