]> git.proxmox.com Git - rustc.git/blob - src/doc/rust-by-example/src/error/multiple_error_types/wrap_error.md
New upstream version 1.63.0+dfsg1
[rustc.git] / src / doc / rust-by-example / src / error / multiple_error_types / wrap_error.md
1 # Wrapping errors
2
3 An alternative to boxing errors is to wrap them in your own error type.
4
5 ```rust,editable
6 use std::error;
7 use std::error::Error;
8 use std::num::ParseIntError;
9 use std::fmt;
10
11 type Result<T> = std::result::Result<T, DoubleError>;
12
13 #[derive(Debug)]
14 enum DoubleError {
15 EmptyVec,
16 // We will defer to the parse error implementation for their error.
17 // Supplying extra info requires adding more data to the type.
18 Parse(ParseIntError),
19 }
20
21 impl fmt::Display for DoubleError {
22 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
23 match *self {
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"),
30 }
31 }
32 }
33
34 impl error::Error for DoubleError {
35 fn source(&self) -> Option<&(dyn error::Error + 'static)> {
36 match *self {
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),
42 }
43 }
44 }
45
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)
52 }
53 }
54
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>()?;
60
61 Ok(2 * parsed)
62 }
63
64 fn print(result: Result<i32>) {
65 match result {
66 Ok(n) => println!("The first doubled is {}", n),
67 Err(e) => {
68 println!("Error: {}", e);
69 if let Some(source) = e.source() {
70 println!(" Caused by: {}", source);
71 }
72 },
73 }
74 }
75
76 fn main() {
77 let numbers = vec!["42", "93", "18"];
78 let empty = vec![];
79 let strings = vec!["tofu", "93", "18"];
80
81 print(double_first(numbers));
82 print(double_first(empty));
83 print(double_first(strings));
84 }
85 ```
86
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
89 for you.
90
91 ### See also:
92
93 [`From::from`][from] and [`Enums`][enums]
94
95 [from]: https://doc.rust-lang.org/std/convert/trait.From.html
96 [enums]: ../../custom_types/enum.md