Easier errors
You may have noticed that it is rather cumbersome to write all those From
methods to convert existing errors into our own variant. Fortunately, a crate exists to make this job easier: thiserror.
After adding thiserror
to your Cargo.toml
$ cargo add thiserror
you will be able to define your Error
type as follows:
#![allow(unused)] fn main() { #[derive(Debug, thiserror::Error)] enum Error { #[error("Wrong HTTP status code: {0}")] BadHttpResult(u16), #[error(transparent)] Io(#[from] std::io::Error), #[error(transparent)] ReqwestError(#[from] reqwest::Error), } }
Our Error
type looks the same as before with a few additions:
- It derives
thiserror::Error
. This is the heart of thethiserror
crate and makes the other things below work. Behind the scenes, it uses "procedural macros" which is a way to transform some Rust code into another Rust code during the compilation. - The
#[error]
attribute indicates how to display the error.{0}
refers to the first field. The fields could also be named, a fieldxyz
would use{xyz}
in the#[error]
attribute. If you are encapsulating another error, you may usetransparent
to indicate that you simply want to display the inner error, and that you have nothing to add. - The
#[from]
attribute on the field of a variant indicates that aFrom
implementation should be generated from the type following#[from]
to anError
. - Your
Error
type will implement thestd::error::Error
trait which allows proper error chaining: the system will know (and will be able to display) that the cause of aError::ReqwestError
is areqwest::Error
, which might also be caused by another deeper error, and so on.
Exercise 5.a: modify your Error
type to use thiserror
and remove your existing From
implementations.
Check that everything still works, including when you make errors happens by changing the urls or the file name.