Reputation: 737
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
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
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