Reputation: 9627
I have a function that reads a file line by line and parses. Right now to i32
but really I'd like this to be templated. Just keeping things simple for now.
I can get it sorted out using explicit for-loops, but not using iterators.
The below code complains that the error type can't be converted to the Box<dyn Error>
type and I'm not sure what to do about that. Aren't the parse errors part of the standard library and thus implement the Error
trait, and doesn't Box
do automatic conversion of errors (because it's such a common idiom?)
use std::error::Error;
use std::fs;
pub fn read_file_to_list(filename: &str) -> Result<Vec<i32>, Box<dyn Error>> {
let file_as_string = fs::read_to_string(filename)?;
file_as_string.lines().map(|line| line.parse()).collect()
}
Error is in the parse
:
Compiling playground v0.0.1 (/playground)
error[E0271]: type mismatch resolving `<i32 as FromStr>::Err == Box<dyn std::error::Error>`
--> src/lib.rs:6:44
|
6 | file_as_string.lines().map(|line| line.parse()).collect()
| ^^^^^ expected struct `ParseIntError`, found struct `Box`
|
= note: expected struct `ParseIntError`
found struct `Box<dyn std::error::Error>`
I assume I'll need to do some sort of map_err
but I can't figure out what and how.
Upvotes: 0
Views: 123
Reputation: 117711
Luckily, conversion from ParseIntError
to Box<dyn Error>
can be done using the Into
trait as there is a blanket impl for that in the stdlib. So we can replace line.parse()
with
line.parse().map_err(|e| e.into())
or:
line.parse().map_err(Into::into)
A common trick to make this more ergonomic is abusing the fact that ?
automatically calls .into()
on the error type:
Ok(line.parse()?)
It looks a bit silly to use ?
only to wrap in Ok
, but it's actually a common idiom precisely for this purpose. So this compiles:
pub fn read_file_to_list(filename: &str) -> Result<Vec<i32>, Box<dyn Error>> {
let file_as_string = fs::read_to_string(filename)?;
file_as_string.lines().map(|line| Ok(line.parse()?)).collect()
}
Upvotes: 3