3 An alternative to boxing errors is to wrap them in your own error type.
8 use std::num::ParseIntError;
11 type Result<T> = std::result::Result<T, DoubleError>;
16 // We will defer to the parse error implementation for their error.
17 // Supplying extra info requires adding more data to the type.
21 impl fmt::Display for DoubleError {
22 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
24 DoubleError::EmptyVec =>
25 write!(f, "please use a vector with at least one element"),
26 // The wrapped error contains additional information and is available
27 // via the source() method.
28 DoubleError::Parse(..) =>
29 write!(f, "the provided string could not be parsed as int"),
34 impl error::Error for DoubleError {
35 fn source(&self) -> Option<&(dyn error::Error + 'static)> {
37 DoubleError::EmptyVec => None,
38 // The cause is the underlying implementation error type. Is implicitly
39 // cast to the trait object `&error::Error`. This works because the
40 // underlying type already implements the `Error` trait.
41 DoubleError::Parse(ref e) => Some(e),
46 // Implement the conversion from `ParseIntError` to `DoubleError`.
47 // This will be automatically called by `?` if a `ParseIntError`
48 // needs to be converted into a `DoubleError`.
49 impl From<ParseIntError> for DoubleError {
50 fn from(err: ParseIntError) -> DoubleError {
51 DoubleError::Parse(err)
55 fn double_first(vec: Vec<&str>) -> Result<i32> {
56 let first = vec.first().ok_or(DoubleError::EmptyVec)?;
57 // Here we implicitly use the `ParseIntError` implementation of `From` (which
58 // we defined above) in order to create a `DoubleError`.
59 let parsed = first.parse::<i32>()?;
64 fn print(result: Result<i32>) {
66 Ok(n) => println!("The first doubled is {}", n),
68 println!("Error: {}", e);
69 if let Some(source) = e.source() {
70 println!(" Caused by: {}", source);
77 let numbers = vec!["42", "93", "18"];
79 let strings = vec!["tofu", "93", "18"];
81 print(double_first(numbers));
82 print(double_first(empty));
83 print(double_first(strings));
87 This adds a bit more boilerplate for handling errors and might not be needed in
88 all applications. There are some libraries that can take care of the boilerplate
93 [`From::from`][from] and [`Enums`][enums]
95 [from]: https://doc.rust-lang.org/std/convert/trait.From.html
96 [enums]: ../../custom_types/enum.md