errors5 solution

This commit is contained in:
mo8it 2024-06-26 18:21:19 +02:00
parent 720b280bc1
commit 129884aff7
3 changed files with 96 additions and 52 deletions

View file

@ -1,38 +1,18 @@
// This program uses an altered version of the code from errors4. // 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
// This exercise uses some concepts that we won't get to until later in the // `From` trait. It's not important to understand them in detail right now, but
// course, like `Box` and the `From` trait. It's not important to understand // you can read ahead if you like. For now, think of the `Box<dyn ???>` type as
// them in detail right now, but you can read ahead if you like. For now, think // an "I want anything that does ???" type.
// of the `Box<dyn ???>` type as an "I want anything that does ???" type, which,
// given Rust's usual standards for runtime safety, should strike you as
// somewhat lenient!
// //
// In short, this particular use case for boxes is for when you want to own a // 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 // 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<dyn Trait> where Trait is // trait. To do so, The `Box` is declared as of type `Box<dyn Trait>` where
// the trait the compiler looks for on any value used in that context. For this // `Trait` is the trait the compiler looks for on any value used in that
// exercise, that context is the potential errors which can be returned in a // context. For this exercise, that context is the potential errors which
// Result. // 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?
use std::error; use std::error::Error;
use std::fmt; use std::fmt;
use std::num::ParseIntError;
// TODO: update the return type of `main()` to make this compile.
fn main() -> Result<(), Box<dyn ???>> {
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)] #[derive(PartialEq, Debug)]
enum CreationError { enum CreationError {
@ -40,17 +20,7 @@ enum CreationError {
Zero, Zero,
} }
impl PositiveNonzeroInteger { // This is required so that `CreationError` can implement `Error`.
fn new(value: i64) -> Result<PositiveNonzeroInteger, CreationError> {
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`.
impl fmt::Display for CreationError { impl fmt::Display for CreationError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let description = match *self { 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<PositiveNonzeroInteger, CreationError> {
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<dyn ???>>`. 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(())
}

View file

@ -692,24 +692,23 @@ name = "errors5"
dir = "13_error_handling" dir = "13_error_handling"
test = false test = false
hint = """ hint = """
There are two different possible `Result` types produced within `main()`, which There are two different possible `Result` types produced within the `main`
are propagated using `?` operators. How do we declare a return type from function, which are propagated using the `?` operators. How do we declare a
`main()` that allows both? return type for the `main` function that allows both?
Under the hood, the `?` operator calls `From::from` on the error value to Under the hood, the `?` operator calls `From::from` on the error value to
convert it to a boxed trait object, a `Box<dyn error::Error>`. This boxed trait convert it to a boxed trait object, a `Box<dyn Error>`. This boxed trait object
object is polymorphic, and since all errors implement the `error::Error` trait, is polymorphic, and since all errors implement the `Error` trait, we can capture
we can capture lots of different errors in one "Box" object. 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 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: Read more about boxing errors:
https://doc.rust-lang.org/stable/rust-by-example/error/multiple_error_types/boxing_errors.html 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: 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]] [[exercises]]
name = "errors6" name = "errors6"

View file

@ -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<dyn ???>` 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<dyn Trait>` 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<PositiveNonzeroInteger, CreationError> {
match value {
x if x < 0 => Err(CreationError::Negative),
0 => Err(CreationError::Zero),
x => Ok(PositiveNonzeroInteger(x as u64)),
}
}
}
fn main() -> Result<(), Box<dyn Error>> {
let pretend_user_input = "42";
let x: i64 = pretend_user_input.parse()?;
println!("output={:?}", PositiveNonzeroInteger::new(x)?);
Ok(())
}