Reputation: 8162
Is there any way to simplify this code?
fn parse(line: &str) -> Result<(usize, f64), String> {
let mut it = line.split_whitespace();
let n = it.next().ok_or("Invalid line")?;
let n = n.parse::<usize>().map_err(|e| e.to_string())?;
let f = it.next().ok_or("Invalid line")?;
let f = f.parse::<f64>().map_err(|e| e.to_string())?;
Ok((n, f))
}
fn main() {
println!("Results: {:?}", parse("5 17.2").unwrap())
}
In real code I need to parse 4 values in line,
and it is boring to write .map_err(|e| e.to_string())
As I understand it, it is impossible to implement std::convert::From
for ParseIntError
/ ParseFloatError
-> String
, because none of the types are defined in my code, am I right?
I see one way to simplify this code:
fn econv<E: ToString>(e: E) -> String {
e.to_string()
}
and use .map_err(econv)
. Are there any other options to simplify my code?
Upvotes: 4
Views: 889
Reputation: 432219
I'd introduce a dedicated error type. If needed, I'd then transform the error into a string once after that:
#[macro_use]
extern crate quick_error;
quick_error! {
#[derive(Debug)]
pub enum Error {
InvalidLine {}
Int(err: std::num::ParseIntError) {
from()
}
Float(err: std::num::ParseFloatError) {
from()
}
}
}
fn parse_inner(line: &str) -> Result<(usize, f64), Error> {
let mut it = line.split_whitespace();
let n = it.next().ok_or(Error::InvalidLine)?;
let n = n.parse()?;
let f = it.next().ok_or(Error::InvalidLine)?;
let f = f.parse()?;
Ok((n, f))
}
fn parse(line: &str) -> Result<(usize, f64), String> {
parse_inner(line).map_err(|e| e.to_string())
}
fn main() {
println!("Results: {:?}", parse("5 17.2").unwrap())
}
Upvotes: 2
Reputation: 300439
Well, a not too terrible option would simply be to create a function to abstract over the repetition:
use std::fmt::Display;
use std::iter::Iterator;
use std::str::FromStr;
fn parse_next<'a, Target, T>(it: &mut T) -> Result<Target, String>
where
T: Iterator<Item = &'a str>,
Target: FromStr,
<Target as FromStr>::Err: Display
{
it.next().ok_or("Invalid line")?.parse::<Target>().map_err(|e| e.to_string())
}
fn parse(line: &str) -> Result<(usize, f64), String> {
let mut it = line.split_whitespace();
Ok((parse_next(&mut it)?, parse_next(&mut it)?))
}
fn main() {
println!("Results: {:?}", parse("5 17.2").unwrap())
}
Upvotes: 3