Lost on how to proceed with rustlings exercise on errors

Im lost here how to fix this to pass the test. I am not even sure how to phrase the question.

    fn parse(s: &str) -> Result<Self, ParsePosNonzeroError> {
        // TODO: change this to return an appropriate error instead of panicking
        // when `parse()` returns an error.
        let x: i64 = s.parse().unwrap();
        Self::new(x).map_err(ParsePosNonzeroError::from_creation)
    }

This is the test result:

thread 'test::test_parse_error' panicked at exercises/13_error_handling/errors6.rs:49:32:

Line 49 is the code above with the parse() in it.

Do I process the s.parse() without an unwrap()? If I do I get some Result within a Result.
What is going on with the second line? Is it trying to use a custom error message? How would I change that?

This is from the rusltings course, exercise errors6.rs.

.parse() returns a Result, and .unwrap() matches against a Result and if it's the Result:Err variant it panics, otherwise it returns the content of Result::Ok

The parse line is essentially saying "parse, and if theres an error, panic"

The second line with Self::new(x).map_err(...) depends on what Self::new returns and what Self even is. it looks like Self should have a .map_err() implementation, or Self::new returns a Result.

.map_err() is just a match which applies the function you pass in to the Err variant of Result, replacing it with the functions return. Its a way to change between error types.

I highly recommend using your IDEs "Jump to Source" feature or even the feature to inline the functions to visualize what they do. (in rust-analyzer, inlining a function is a Code Action)

I hope these tips help you go forward from here and learn for yourself what you're intended to change.

1 Like

I want to do this but I am getting an error on the parse:

the trait bound PositiveNonzeroInteger: FromStr is not satisfied

    fn parse(s: &str) -> Result<Self, ParsePosNonzeroError> {
        match s.parse() {
            Ok(num) => Ok(num),
            Err(err) => Err(err),
        }
    }

I feel like this is the solution, but I need to somehow change the return error type into something else like: Err(err) => Err(ParsePosNonzeroError),

Yes, and the way you spell that is this:

Err(err) => Err(ParsePosNonzeroError::ParseInt(err)),

You will then also have to do something similar with the Ok branch so that

  • you're asking s.parse() to give you an i64, not a PositiveNonzeroInteger which it doesn’t know about (FromStr) not implemented.
  • you pass along the possible error from creation, like the code you started with does.
Solution

You can reuse the final line of the original code:

Ok(num) => Self::new(x).map_err(ParsePosNonzeroError::from_creation),

I don't understand the solution, why I missed it, and how to ask for help. Rust makes me feel stupid, I just cant get a grasp of what I am missing. I read the docs. I cant even figure out how to ask for help let alone understand the help that is given. Never had any problem with other languages.

It may be more helpful to write it out as a match statement first, then adding map_err later on (clippy may suggest it, which can help with learning)

From the solution snippet above:

Ok(num) => match Self::new(x) {
    Ok(nonzero) => Ok(nonzero),
    Err(err) => Err(ParsePosNonzeroError::from_creation(err)),
}

There's something nice about nested matches, where you can follow the logic through each branch. The original exercise seems to want you to use map_err and friends, but at the beginning this may obscure too much from view.

4 Likes