Structs

Deriving Standard Traits

The #[derive(...)] attribute instructs the compiler to automatically generate standard trait implementations for a struct by delegating the operation field-by-field in declaration order. A trait can be derived on a struct only if every field of the struct also implements that trait.

Built-In Derivable Standard Library Traits

Trait in #[derive(...)] Generated Method(s) What the Derived Implementation Does
Debug fmt(&self, f: &mut Formatter) Formats the struct name and all fields for {:?} and {:#?}
Clone clone(&self) -> Self Calls .clone() on every field to produce a deep duplicate
Copy (marker trait; requires Clone) Marks the struct as bitwise-copyable on assignment (all fields must be Copy, and the struct cannot implement Drop)
PartialEq eq(&self, other: &Self) -> bool Enables == and !=; returns true if every field equals the corresponding field in other
Eq (marker trait; requires PartialEq) Asserts that == is reflexive (a == a), which holds for integers/strings but not f32/f64 (NaN != NaN)
PartialOrd partial_cmp(&self, other: &Self) Enables <, <=, >, >= by comparing fields lexicographically from top to bottom
Ord cmp(&self, other: &Self) -> Ordering Total lexicographical ordering (requires Eq and PartialOrd); needed for BTreeMap keys and .sort()
Hash hash<H: Hasher>(&self, state: &mut H) Feeds every field into the hasher in order; needed (with Eq) for HashMap keys and HashSet elements
Default default() -> Self Initializes every field with FieldType::default()

Deriving Common Traits Together

For plain value structs that do not contain floating-point numbers, it is idiomatic to derive Debug, Clone, PartialEq, Eq, Hash, Default (and Copy if the struct is small and contains only Copy fields):

use std::collections::HashSet;

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
struct Version {
    major: u16,
    minor: u16,
    patch: u16,
}

fn main() {
    // 1. `Default` creates `0.0.0`
    let v0 = Version::default();

    // 2. `Copy` + `Clone` allow copying without moving
    let v1 = Version { major: 1, minor: 80, patch: 0 };
    let v2 = Version { major: 1, minor: 85, patch: 1 };

    // 3. `Ord` + `PartialOrd` compare fields top-to-bottom (`major`, then `minor`, then `patch`)
    let mut releases = [v2, v0, v1];
    releases.sort();
    println!("Sorted releases ({:?}):", releases);

    // 4. `Hash` + `Eq` allow storing `Version` in a `HashSet` or `HashMap`
    let mut seen = HashSet::new();
    seen.insert(v1);
    println!("Set contains v1? {}", seen.contains(&v1));
}
Sorted releases ([Version { major: 0, minor: 0, patch: 0 }, Version { major: 1, minor: 80, patch: 0 }, Version { major: 1, minor: 85, patch: 1 }]):
Set contains v1? true

Field Declaration Order Affects Derived PartialOrd and Ord

Because derived PartialOrd and Ord compare fields from first to last as declared in the struct, always place the primary sort key first:

#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
struct Task {
    priority: u8, // Compared 1st
    id: u32,      // Compared 2nd (tie-breaker)
}

fn main() {
    let t1 = Task { priority: 1, id: 999 };
    let t2 = Task { priority: 2, id: 1 };

    // `t1 < t2` is true because `priority: 1 < priority: 2`, regardless of `id`:
    println!("t1 < t2: {}", t1 < t2);
}
t1 < t2: true

How #[derive] Interacts with Generic Structs

When you write #[derive(Clone, Debug)] on a generic struct struct Wrapper<T>(T), the macro expands to a conditionally bounded implementation:

// Generated automatically by `#[derive(Clone)]` on `struct Wrapper<T>(T)`:
// impl<T: Clone> Clone for Wrapper<T> { ... }

This means Wrapper<T> implements Clone whenever T implements Clone, and still compiles cleanly even when instantiated with a type T that does not implement Clone.