diff options
Diffstat (limited to '')
-rw-r--r-- | src/doc/rust-by-example/src/error/multiple_error_types/wrap_error.md | 96 |
1 files changed, 96 insertions, 0 deletions
diff --git a/src/doc/rust-by-example/src/error/multiple_error_types/wrap_error.md b/src/doc/rust-by-example/src/error/multiple_error_types/wrap_error.md new file mode 100644 index 000000000..3da598493 --- /dev/null +++ b/src/doc/rust-by-example/src/error/multiple_error_types/wrap_error.md @@ -0,0 +1,96 @@ +# Wrapping errors + +An alternative to boxing errors is to wrap them in your own error type. + +```rust,editable +use std::error; +use std::error::Error; +use std::num::ParseIntError; +use std::fmt; + +type Result<T> = std::result::Result<T, DoubleError>; + +#[derive(Debug)] +enum DoubleError { + EmptyVec, + // We will defer to the parse error implementation for their error. + // Supplying extra info requires adding more data to the type. + Parse(ParseIntError), +} + +impl fmt::Display for DoubleError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + DoubleError::EmptyVec => + write!(f, "please use a vector with at least one element"), + // The wrapped error contains additional information and is available + // via the source() method. + DoubleError::Parse(..) => + write!(f, "the provided string could not be parsed as int"), + } + } +} + +impl error::Error for DoubleError { + fn source(&self) -> Option<&(dyn error::Error + 'static)> { + match *self { + DoubleError::EmptyVec => None, + // The cause is the underlying implementation error type. Is implicitly + // cast to the trait object `&error::Error`. This works because the + // underlying type already implements the `Error` trait. + DoubleError::Parse(ref e) => Some(e), + } + } +} + +// Implement the conversion from `ParseIntError` to `DoubleError`. +// This will be automatically called by `?` if a `ParseIntError` +// needs to be converted into a `DoubleError`. +impl From<ParseIntError> for DoubleError { + fn from(err: ParseIntError) -> DoubleError { + DoubleError::Parse(err) + } +} + +fn double_first(vec: Vec<&str>) -> Result<i32> { + let first = vec.first().ok_or(DoubleError::EmptyVec)?; + // Here we implicitly use the `ParseIntError` implementation of `From` (which + // we defined above) in order to create a `DoubleError`. + let parsed = first.parse::<i32>()?; + + Ok(2 * parsed) +} + +fn print(result: Result<i32>) { + match result { + Ok(n) => println!("The first doubled is {}", n), + Err(e) => { + println!("Error: {}", e); + if let Some(source) = e.source() { + println!(" Caused by: {}", source); + } + }, + } +} + +fn main() { + let numbers = vec!["42", "93", "18"]; + let empty = vec![]; + let strings = vec!["tofu", "93", "18"]; + + print(double_first(numbers)); + print(double_first(empty)); + print(double_first(strings)); +} +``` + +This adds a bit more boilerplate for handling errors and might not be needed in +all applications. There are some libraries that can take care of the boilerplate +for you. + +### See also: + +[`From::from`][from] and [`Enums`][enums] + +[from]: https://doc.rust-lang.org/std/convert/trait.From.html +[enums]: ../../custom_types/enum.md |