diff options
Diffstat (limited to 'src/doc/rust-by-example/src/error/multiple_error_types/define_error_type.md')
-rw-r--r-- | src/doc/rust-by-example/src/error/multiple_error_types/define_error_type.md | 68 |
1 files changed, 68 insertions, 0 deletions
diff --git a/src/doc/rust-by-example/src/error/multiple_error_types/define_error_type.md b/src/doc/rust-by-example/src/error/multiple_error_types/define_error_type.md new file mode 100644 index 000000000..4c374276d --- /dev/null +++ b/src/doc/rust-by-example/src/error/multiple_error_types/define_error_type.md @@ -0,0 +1,68 @@ +# Defining an error type + +Sometimes it simplifies the code to mask all of the different errors with a +single type of error. We'll show this with a custom error. + +Rust allows us to define our own error types. In general, a "good" error type: + +* Represents different errors with the same type +* Presents nice error messages to the user +* Is easy to compare with other types + - Good: `Err(EmptyVec)` + - Bad: `Err("Please use a vector with at least one element".to_owned())` +* Can hold information about the error + - Good: `Err(BadChar(c, position))` + - Bad: `Err("+ cannot be used here".to_owned())` +* Composes well with other errors + +```rust,editable +use std::fmt; + +type Result<T> = std::result::Result<T, DoubleError>; + +// Define our error types. These may be customized for our error handling cases. +// Now we will be able to write our own errors, defer to an underlying error +// implementation, or do something in between. +#[derive(Debug, Clone)] +struct DoubleError; + +// Generation of an error is completely separate from how it is displayed. +// There's no need to be concerned about cluttering complex logic with the display style. +// +// Note that we don't store any extra info about the errors. This means we can't state +// which string failed to parse without modifying our types to carry that information. +impl fmt::Display for DoubleError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "invalid first item to double") + } +} + +fn double_first(vec: Vec<&str>) -> Result<i32> { + vec.first() + // Change the error to our new type. + .ok_or(DoubleError) + .and_then(|s| { + s.parse::<i32>() + // Update to the new error type here also. + .map_err(|_| DoubleError) + .map(|i| 2 * i) + }) +} + +fn print(result: Result<i32>) { + match result { + Ok(n) => println!("The first doubled is {}", n), + Err(e) => println!("Error: {}", e), + } +} + +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)); +} +``` |