]> git.proxmox.com Git - rustc.git/blame - 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
CommitLineData
2c00a5a8
XL
1# Wrapping errors
2
3An alternative to boxing errors is to wrap them in your own error type.
4
5```rust,editable
6use std::error;
923072b8 7use std::error::Error;
2c00a5a8
XL
8use std::num::ParseIntError;
9use std::fmt;
10
11type Result<T> = std::result::Result<T, DoubleError>;
12
13#[derive(Debug)]
14enum 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
21impl 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"),
1b1a35ee
XL
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"),
2c00a5a8
XL
30 }
31 }
32}
33
34impl error::Error for DoubleError {
532ac7d7 35 fn source(&self) -> Option<&(dyn error::Error + 'static)> {
2c00a5a8
XL
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`.
49impl From<ParseIntError> for DoubleError {
50 fn from(err: ParseIntError) -> DoubleError {
51 DoubleError::Parse(err)
52 }
53}
54
55fn double_first(vec: Vec<&str>) -> Result<i32> {
56 let first = vec.first().ok_or(DoubleError::EmptyVec)?;
1b1a35ee
XL
57 // Here we implicitly use the `ParseIntError` implementation of `From` (which
58 // we defined above) in order to create a `DoubleError`.
2c00a5a8
XL
59 let parsed = first.parse::<i32>()?;
60
61 Ok(2 * parsed)
62}
63
64fn print(result: Result<i32>) {
65 match result {
66 Ok(n) => println!("The first doubled is {}", n),
1b1a35ee
XL
67 Err(e) => {
68 println!("Error: {}", e);
69 if let Some(source) = e.source() {
70 println!(" Caused by: {}", source);
71 }
72 },
2c00a5a8
XL
73 }
74}
75
76fn 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
87This adds a bit more boilerplate for handling errors and might not be needed in
88all applications. There are some libraries that can take care of the boilerplate
89for 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
dc9dc135 96[enums]: ../../custom_types/enum.md