Michael Ilyin
Michael Ilyin

Reputation: 737

How to construct a ParseIntError in my own code?

I want to reuse the standard library's ParseIntError in my function. However, I'm implementing parsing of the input string myself, so I don't need to return an error value returned by the standard library.

I didn't find a way to construct ParseIntError value. The only solution I found looks like this:

use std::num::ParseIntError;

fn from_str_radix(s: &str, radix: u32) -> Result<(), ParseIntError> {
    let error_empty = "".parse::<i32>().expect_err("get empty input error");
    let error_invalid_digit = "Z".parse::<i32>().expect_err("get invalid digit error");

    if s.is_empty() {
        return Err(error_empty);
    }

    for c in s.chars().rev() {
        match c.to_digit(radix) {
            None => return Err(error_invalid_digit),
            _ => unimplemented!(),
        }
    }

    Ok(())
}

Is there more elegant way to return ParseIntError from my own code?

Upvotes: 6

Views: 6417

Answers (2)

Jessica Pennell
Jessica Pennell

Reputation: 578

The accepted answer is literally correct, and contains best practices.

Nonetheless, when learning rust with rustlings, chapter 13 problem 3 put me in an impossible position. When learning to use the ? operator on Results, and using a function written in a previous tutorial chapter (and thus impossible to modify while staying within the constraints of the problem provided) which uses <ParseIntError> as a return type, there was a line marked "Don't change this line" which forced me to discard the returned ParseIntError, while at the same time returning ParseIntError correctly. The solution they give does not provide an error output at all (which is not incorrect, since the ? operator does the job, but also not very informative when you are learning a language).

I suppose it may have been possible to return a more generic type but in languages that throw specific errors I tend to view discarding that information as a bad practice. And I am using rustlings to learn.

So while it is impossible to construct a ParseIntError it is very easy to generate a ParseIntError. They actually do this several times in the documentation, https://doc.rust-lang.org/std/num/struct.ParseIntError.html .

i32::from_str_radix("a12", 10)

If you run that example I copied from the documentation in a compiler you will see that that is equivalent to

"a12".parse::<i32>()

Since the failing text ends up in the error message, this means you effectively have a factory which will construct ParseIntErrors for you, that is,

desired_err_msg.parse::<i32>()

You can capture all the information you were trying to capture above in that single line. Need an invalid digit? Provide an invalid digit :)

Upvotes: 0

Stargateur
Stargateur

Reputation: 26757

There is currently no way to construct a ParseIntError yourself. As you find it, there is an open issue that asks to make it public. However, I don't think it's a good idea.

ParseIntError is the error of num module. It isn't made to be used by everyone that would implement a parsing crate because you should have your own potential error. You could use IntErrorKind but I still don't think is a good thing because you could end by not having the same error.

So, I think you should have your own error type, and maybe use the same design, have an enum with #[non_exhaustive] attribute. You should not hesitate to use your own error in your own code. See very good article Error Handling In Rust - A Deep Dive. (I personally doesn't agree with everything in the article but that still high quality, I recommend using snafu or thiserror)

Upvotes: 5

Related Questions