In various places in the book, we’ve discussed the
derive attribute, which you can apply to a struct or enum definition. The
derive attribute generates code that will implement a trait with its own default implementation on the type you’ve annotated with the
In this appendix, we provide a reference of all the traits in the standard library that you can use with
derive. Each section covers:
If you want different behavior from that provided by the
derive attribute, consult the standard library documentation for each trait for details of how to manually implement them.
The rest of the traits defined in the standard library can’t be implemented on your types using
derive. These traits don’t have sensible default behavior, so it’s up to you to implement them in the way that makes sense for what you’re trying to accomplish.
An example of a trait that can’t be derived is
Display, which handles formatting for end users. You should always consider the appropriate way to display a type to an end user. What parts of the type should an end user be allowed to see? What parts would they find relevant? What format of the data would be most relevant to them? The Rust compiler doesn’t have this insight, so it can’t provide appropriate default behavior for you.
The list of derivable traits provided in this appendix is not comprehensive: libraries can implement
derive for their own traits, making the list of traits you can use
derive with truly open-ended. Implementing
derive involves using a procedural macro, which is covered in the “Macros” section of Chapter 19.
Debugfor Programmer Output
Debug trait enables debug formatting in format strings, which you indicate by adding
Debug trait allows you to print instances of a type for debugging purposes, so you and other programmers using your type can inspect an instance at a particular point in a program’s execution.
Debug trait is required, for example, in use of the
assert_eq! macro. This macro prints the values of instances given as arguments if the equality assertion fails so programmers can see why the two instances weren’t equal.
Eqfor Equality Comparisons
PartialEq trait allows you to compare instances of a type to check for equality and enables use of the
PartialEq implements the
eq method. When
PartialEq is derived on structs, two instances are equal only if all fields are equal, and the instances are not equal if any fields are not equal. When derived on enums, each variant is equal to itself and not equal to the other variants.
PartialEq trait is required, for example, with the use of the
assert_eq! macro, which needs to be able to compare two instances of a type for equality.
Eq trait has no methods. Its purpose is to signal that for every value of the annotated type, the value is equal to itself. The
Eq trait can only be applied to types that also implement
PartialEq, although not all types that implement
PartialEq can implement
Eq. One example of this is floating point number types: the implementation of floating point numbers states that two instances of the not-a-number (
NaN) value are not equal to each other.
An example of when
Eq is required is for keys in a
HashMap<K, V> so the
HashMap<K, V> can tell whether two keys are the same.
Ordfor Ordering Comparisons
PartialOrd trait allows you to compare instances of a type for sorting purposes. A type that implements
PartialOrd can be used with the
>= operators. You can only apply the
PartialOrd trait to types that also implement
PartialOrd implements the
partial_cmp method, which returns an
Option<Ordering> that will be
None when the values given don’t produce an ordering. An example of a value that doesn’t produce an ordering, even though most values of that type can be compared, is the not-a-number (
NaN) floating point value. Calling
partial_cmp with any floating point number and the
NaN floating point value will return
When derived on structs,
PartialOrd compares two instances by comparing the value in each field in the order in which the fields appear in the struct definition. When derived on enums, variants of the enum declared earlier in the enum definition are considered less than the variants listed later.
PartialOrd trait is required, for example, for the
gen_range method from the
rand crate that generates a random value in the range specified by a low value and a high value.
Ord trait allows you to know that for any two values of the annotated type, a valid ordering will exist. The
Ord trait implements the
cmp method, which returns an
Ordering rather than an
Option<Ordering> because a valid ordering will always be possible. You can only apply the
Ord trait to types that also implement
PartialEq). When derived on structs and enums,
cmp behaves the same way as the derived implementation for
partial_cmp does with
An example of when
Ord is required is when storing values in a
BTreeSet<T>, a data structure that stores data based on the sort order of the values.
Copyfor Duplicating Values
Clone trait allows you to explicitly create a deep copy of a value, and the duplication process might involve running arbitrary code and copying heap data. See the “Ways Variables and Data Interact: Clone” section in Chapter 4 for more information on
Clone implements the
clone method, which when implemented for the whole type, calls
clone on each of the parts of the type. This means all the fields or values in the type must also implement
Clone to derive
An example of when
Clone is required is when calling the
to_vec method on a slice. The slice doesn’t own the type instances it contains, but the vector returned from
to_vec will need to own its instances, so
clone on each item. Thus, the type stored in the slice must implement
Copy trait allows you to duplicate a value by only copying bits stored on the stack; no arbitrary code is necessary. See the “Stack-Only Data: Copy” section in Chapter 4 for more information on
Copy trait doesn’t define any methods to prevent programmers from overloading those methods and violating the assumption that no arbitrary code is being run. That way, all programmers can assume that copying a value will be very fast.
You can derive
Copy on any type whose parts all implement
Copy. You can only apply the
Copy trait to types that also implement
Clone, because a type that implements
Copy has a trivial implementation of
Clone that performs the same task as
Copy trait is rarely required; types that implement
Copy have optimizations available, meaning you don’t have to call
clone, which makes the code more concise.
Everything possible with
Copy you can also accomplish with
Clone, but the code might be slower or have to use
clone in places.
Hashfor Mapping a Value to a Value of Fixed Size
Hash trait allows you to take an instance of a type of arbitrary size and map that instance to a value of fixed size using a hash function. Deriving
Hash implements the
hash method. The derived implementation of the
hash method combines the result of calling
hash on each of the parts of the type, meaning all fields or values must also implement
Hash to derive
An example of when
Hash is required is in storing keys in a
HashMap<K, V> to store data efficiently.
Defaultfor Default Values
Default trait allows you to create a default value for a type. Deriving
Default implements the
default function. The derived implementation of the
default function calls the
default function on each part of the type, meaning all fields or values in the type must also implement
Default to derive
Default::default function is commonly used in combination with the struct update syntax discussed in the “Creating Instances From Other Instances With Struct Update Syntax” section in Chapter 5. You can customize a few fields of a struct and then set and use a default value for the rest of the fields by using
Default trait is required when you use the method
Option<T> instances, for example. If the
None, the method
unwrap_or_default will return the result of
Default::default for the type
T stored in the
© 2010 The Rust Project Developers
Licensed under the Apache License, Version 2.0 or the MIT license, at your option.