blob: eafd36a978806627ab71a1f3e01b52c977c845ca [file] [log] [blame] [view] [edit]
## Appendix C: Derivable Traits
In various places in the book, weve 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
youve annotated with the `derive` syntax.
In this appendix, we provide a reference of all the traits in the standard
library that you can use with `derive`. Each section covers:
* What operators and methods deriving this trait will enable
* What the implementation of the trait provided by `derive` does
* What implementing the trait signifies about the type
* The conditions in which youre allowed or not allowed to implement the trait
* Examples of operations that require the trait
If you want different behavior from that provided by the `derive` attribute,
consult the [standard library documentation](../std/index.html)<!-- ignore -->
for each trait for details of how to manually implement them.
These traits listed here are the only ones defined by the standard library that
can be implemented on your types using `derive`. Other traits defined in the
standard library dont have sensible default behavior, so its up to you to
implement them in the way that makes sense for what youre trying to accomplish.
An example of a trait that cant 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 doesnt have this insight, so
it cant 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”][macros]<!-- ignore -->
section of Chapter 20.
### `Debug` for Programmer Output
The `Debug` trait enables debug formatting in format strings, which you indicate
by adding `:?` within `{}` placeholders.
The `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 programs execution.
The `Debug` trait is required, for example, in using 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 werent equal.
### `PartialEq` and `Eq` for Equality Comparisons
The `PartialEq` trait allows you to compare instances of a type to check for
equality and enables use of the `==` and `!=` operators.
Deriving `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.
The `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.
The `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.
### `PartialOrd` and `Ord` for Ordering Comparisons
The `PartialOrd` trait allows you to compare instances of a type for sorting
purposes. A type that implements `PartialOrd` can be used with the `<`, `>`,
`<=`, and `>=` operators. You can only apply the `PartialOrd` trait to types
that also implement `PartialEq`.
Deriving `PartialOrd` implements the `partial_cmp` method, which returns an
`Option<Ordering>` that will be `None` when the values given dont produce an
ordering. An example of a value that doesnt 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 `None`.
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.
The `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 range
expression.
The `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 `PartialOrd` and `Eq` (and `Eq` requires `PartialEq`). When
derived on structs and enums, `cmp` behaves the same way as the derived
implementation for `partial_cmp` does with `PartialOrd`.
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.
### `Clone` and `Copy` for Duplicating Values
The `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”][ways-variables-and-data-interact-clone]<!-- ignore --> section in
Chapter 4 for more information on `Clone`.
Deriving `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 `Clone`.
An example of when `Clone` is required is when calling the `to_vec` method on a
slice. The slice doesnt own the type instances it contains, but the vector
returned from `to_vec` will need to own its instances, so `to_vec` calls `clone`
on each item. Thus, the type stored in the slice must implement `Clone`.
The `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”][stack-only-data-copy]<!-- ignore --> section in
Chapter 4 for more information on `Copy`.
The `Copy` trait doesnt 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`. A type that
implements `Copy` must also implement `Clone`, because a type that implements
`Copy` has a trivial implementation of `Clone` that performs the same task as
`Copy`.
The `Copy` trait is rarely required; types that implement `Copy` have
optimizations available, meaning you dont 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.
### `Hash` for Mapping a Value to a Value of Fixed Size
The `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 `Hash`.
An example of when `Hash` is required is in storing keys in a `HashMap<K, V>` to
store data efficiently.
### `Default` for Default Values
The `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`.
The `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”][creating-instances-from-other-instances-with-struct-update-syntax]<!-- ignore -->
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::default()`.
The `Default` trait is required when you use the method `unwrap_or_default` on
`Option<T>` instances, for example. If the `Option<T>` is `None`, the method
`unwrap_or_default` will return the result of `Default::default` for the type
`T` stored in the `Option<T>`.
[creating-instances-from-other-instances-with-struct-update-syntax]: ch05-01-defining-structs.html#creating-instances-from-other-instances-with-struct-update-syntax
[stack-only-data-copy]: ch04-01-what-is-ownership.html#stack-only-data-copy
[ways-variables-and-data-interact-clone]: ch04-01-what-is-ownership.html#ways-variables-and-data-interact-clone
[macros]: ch20-06-macros.html#macros