Error trait
Error reporting
In the previous exercise you had to destructure the TitleError
variant to extract the error message and
pass it to the panic!
macro.
This is a (rudimentary) example of error reporting: transforming an error type into a representation that can be
shown to a user, a service operator, or a developer.
It's not practical for each Rust developer to come up with their own error reporting strategy: it'd be a waste of time
and it wouldn't compose well across projects.
That's why Rust provides the std::error::Error
trait.
The Error
trait
There are no constraints on the type of the Err
variant in a Result
, but it's a good practice to use a type
that implements the Error
trait.
Error
is the cornerstone of Rust's error handling story:
// Slightly simplified definition of the `Error` trait
pub trait Error: Debug + Display {}
You might recall the :
syntax from the From
trait—it's used to specify supertraits.
For Error
, there are two supertraits: Debug
and Display
. If a type wants to implement Error
, it must also
implement Debug
and Display
.
Display
and Debug
We've already encountered the Debug
trait in a previous exercise—it's the trait used by
assert_eq!
to display the values of the variables it's comparing when the assertion fails.
From a "mechanical" perspective, Display
and Debug
are identical—they encode how a type should be converted
into a string-like representation:
// `Debug`
pub trait Debug {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error>;
}
// `Display`
pub trait Display {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error>;
}
The difference is in their purpose: Display
returns a representation that's meant for "end-users",
while Debug
provides a low-level representation that's more suitable to developers and service operators.
That's why Debug
can be automatically implemented using the #[derive(Debug)]
attribute, while Display
requires a manual implementation.
Exercise
The exercise for this section is located in 05_ticket_v2/09_error_trait