From 129884aff74964d13aba8309014554b5625d6e5b Mon Sep 17 00:00:00 2001 From: mo8it Date: Wed, 26 Jun 2024 18:21:19 +0200 Subject: [PATCH] errors5 solution --- exercises/13_error_handling/errors5.rs | 76 ++++++++++++-------------- rustlings-macros/info.toml | 17 +++--- solutions/13_error_handling/errors5.rs | 55 ++++++++++++++++++- 3 files changed, 96 insertions(+), 52 deletions(-) diff --git a/exercises/13_error_handling/errors5.rs b/exercises/13_error_handling/errors5.rs index 71925626..d0044db2 100644 --- a/exercises/13_error_handling/errors5.rs +++ b/exercises/13_error_handling/errors5.rs @@ -1,38 +1,18 @@ -// This program uses an altered version of the code from errors4. -// -// This exercise uses some concepts that we won't get to until later in the -// course, like `Box` and the `From` trait. It's not important to understand -// them in detail right now, but you can read ahead if you like. For now, think -// of the `Box` type as an "I want anything that does ???" type, which, -// given Rust's usual standards for runtime safety, should strike you as -// somewhat lenient! +// This exercise is an altered version of the `errors4` exercise. It uses some +// concepts that we won't get to until later in the course, like `Box` and the +// `From` trait. It's not important to understand them in detail right now, but +// you can read ahead if you like. For now, think of the `Box` type as +// an "I want anything that does ???" type. // // In short, this particular use case for boxes is for when you want to own a // value and you care only that it is a type which implements a particular -// trait. To do so, The Box is declared as of type Box where Trait is -// the trait the compiler looks for on any value used in that context. For this -// exercise, that context is the potential errors which can be returned in a -// Result. -// -// What can we use to describe both errors? In other words, is there a trait -// which both errors implement? +// trait. To do so, The `Box` is declared as of type `Box` where +// `Trait` is the trait the compiler looks for on any value used in that +// context. For this exercise, that context is the potential errors which +// can be returned in a `Result`. -use std::error; +use std::error::Error; use std::fmt; -use std::num::ParseIntError; - -// TODO: update the return type of `main()` to make this compile. -fn main() -> Result<(), Box> { - let pretend_user_input = "42"; - let x: i64 = pretend_user_input.parse()?; - println!("output={:?}", PositiveNonzeroInteger::new(x)?); - Ok(()) -} - -// Don't change anything below this line. - -#[derive(PartialEq, Debug)] -struct PositiveNonzeroInteger(u64); #[derive(PartialEq, Debug)] enum CreationError { @@ -40,17 +20,7 @@ enum CreationError { Zero, } -impl PositiveNonzeroInteger { - fn new(value: i64) -> Result { - match value { - x if x < 0 => Err(CreationError::Negative), - x if x == 0 => Err(CreationError::Zero), - x => Ok(PositiveNonzeroInteger(x as u64)), - } - } -} - -// This is required so that `CreationError` can implement `error::Error`. +// This is required so that `CreationError` can implement `Error`. impl fmt::Display for CreationError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let description = match *self { @@ -61,4 +31,26 @@ impl fmt::Display for CreationError { } } -impl error::Error for CreationError {} +impl Error for CreationError {} + +#[derive(PartialEq, Debug)] +struct PositiveNonzeroInteger(u64); + +impl PositiveNonzeroInteger { + fn new(value: i64) -> Result { + match value { + 0 => Err(CreationError::Zero), + x if x < 0 => Err(CreationError::Negative), + x => Ok(PositiveNonzeroInteger(x as u64)), + } + } +} + +// TODO: Add the correct return type `Result<(), Box>`. What can we +// use to describe both errors? Is there a trait which both errors implement? +fn main() { + let pretend_user_input = "42"; + let x: i64 = pretend_user_input.parse()?; + println!("output={:?}", PositiveNonzeroInteger::new(x)?); + Ok(()) +} diff --git a/rustlings-macros/info.toml b/rustlings-macros/info.toml index d39044c0..700c1792 100644 --- a/rustlings-macros/info.toml +++ b/rustlings-macros/info.toml @@ -692,24 +692,23 @@ name = "errors5" dir = "13_error_handling" test = false hint = """ -There are two different possible `Result` types produced within `main()`, which -are propagated using `?` operators. How do we declare a return type from -`main()` that allows both? +There are two different possible `Result` types produced within the `main` +function, which are propagated using the `?` operators. How do we declare a +return type for the `main` function that allows both? Under the hood, the `?` operator calls `From::from` on the error value to -convert it to a boxed trait object, a `Box`. This boxed trait -object is polymorphic, and since all errors implement the `error::Error` trait, -we can capture lots of different errors in one "Box" object. +convert it to a boxed trait object, a `Box`. This boxed trait object +is polymorphic, and since all errors implement the `Error` trait, we can capture +lots of different errors in one `Box` object. -Check out this section of the book: +Check out this section of The Book: https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html#a-shortcut-for-propagating-errors-the--operator Read more about boxing errors: https://doc.rust-lang.org/stable/rust-by-example/error/multiple_error_types/boxing_errors.html Read more about using the `?` operator with boxed errors: -https://doc.rust-lang.org/stable/rust-by-example/error/multiple_error_types/reenter_question_mark.html -""" +https://doc.rust-lang.org/stable/rust-by-example/error/multiple_error_types/reenter_question_mark.html""" [[exercises]] name = "errors6" diff --git a/solutions/13_error_handling/errors5.rs b/solutions/13_error_handling/errors5.rs index 4e181989..c1424eee 100644 --- a/solutions/13_error_handling/errors5.rs +++ b/solutions/13_error_handling/errors5.rs @@ -1 +1,54 @@ -// Solutions will be available before the stable release. Thank you for testing the beta version 🥰 +// This exercise is an altered version of the `errors4` exercise. It uses some +// concepts that we won't get to until later in the course, like `Box` and the +// `From` trait. It's not important to understand them in detail right now, but +// you can read ahead if you like. For now, think of the `Box` type as +// an "I want anything that does ???" type. +// +// In short, this particular use case for boxes is for when you want to own a +// value and you care only that it is a type which implements a particular +// trait. To do so, The `Box` is declared as of type `Box` where +// `Trait` is the trait the compiler looks for on any value used in that +// context. For this exercise, that context is the potential errors which +// can be returned in a `Result`. + +use std::error::Error; +use std::fmt; + +#[derive(PartialEq, Debug)] +enum CreationError { + Negative, + Zero, +} + +// This is required so that `CreationError` can implement `Error`. +impl fmt::Display for CreationError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let description = match *self { + CreationError::Negative => "number is negative", + CreationError::Zero => "number is zero", + }; + f.write_str(description) + } +} + +impl Error for CreationError {} + +#[derive(PartialEq, Debug)] +struct PositiveNonzeroInteger(u64); + +impl PositiveNonzeroInteger { + fn new(value: i64) -> Result { + match value { + x if x < 0 => Err(CreationError::Negative), + 0 => Err(CreationError::Zero), + x => Ok(PositiveNonzeroInteger(x as u64)), + } + } +} + +fn main() -> Result<(), Box> { + let pretend_user_input = "42"; + let x: i64 = pretend_user_input.parse()?; + println!("output={:?}", PositiveNonzeroInteger::new(x)?); + Ok(()) +}