Traits

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 the enum block.
  • #[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)].