In the following code I would like to get the 2nd string in a vector args
and then parse it into an i32
. This code will not complie, however, because i can not call parse()
on the Option value returned by nth()
.
use std::env;
fn main() {
let args: Vec<String> = env::args().collect();
let a = args.iter().nth(1).parse::<i32>();
}
I know i could just use expect()
to unwrap the value, before trying to parse it, however I do not want my code to panic. I want a
to be a Result value that is an Err if either nth()
or parse()
fails, and otherwise is a Ok(Int). Is there a way to accomplish this in rust? Thanks.
It is quite easy if you look in the documentation for either Option
or Result
. The function you are thinking of is likely and_then
which allows you to then provide a closure which can change the Ok
type and value if filled, but otherwise leaves it unchanged when encountering an error. However, you need to do though is decide on a common error type to propagate. Since the Option<&String>
needs to be turned to an error on a None
value we have to choose a type to use.
Here I provide a brief example with a custom error type. I decided to use .get
instead of .iter().nth(1)
since it does the same thing and we might as well take advantage of the Vec
since you have gone to the work of creating it.
use std::num::ParseIntError;
enum ArgParseError {
NotFound(usize),
InvalidArg(ParseIntError),
}
let args: Vec<String> = env::args().collect();
let a: Result<i32, ArgParseError> = args
.get(1) // Option<&String>
.ok_or_else(|| ArgParseError::NotFound(1)) // Result<&String, ArgParseError>
.and_then(|x: &String| {
x.parse::<i32>() // Result<i32, ParseIntError>
.map_err(|e| ArgParseError::InvalidArg(e)) // Result<i32, ArgParseError>
});