Reputation: 3271
fn lines_from_file<F>(filename: F) -> Result<io::Lines<BufReader<File>>, io::Error>
where
F: std::convert::AsRef<std::path::Path>,
{
let file = File::open(filename)?;
Ok(io::BufReader::new(file).lines())
}
fn main() {
let filename: &str = "input.pdl";
// This works fine
match lines_from_file(filename) {
Ok(lines) => {
for line in lines {
println!("{:?}", line);
},
}
Err(e) => println!("Error {:?}", e),
}
}
I'd like to use this instead:
if let lines = Ok(lines_from_file(filename)) {
for line in lines {
println!("{:?}", line);
}
} else {
println!("Error {:?}" /*what goes here?*/,)
}
But that gives an error:
| if let lines = Ok(lines_from_file(filename)) {
| ^^ cannot infer type for `E`
What is the idiomatic way of using an if-let binding when matching a Result
and still being able to capture the error?
Upvotes: 24
Views: 29738
Reputation: 89016
[...] using an if-let binding when matching a Result and still being able to capture the error?
This is fundamentally impossible with one if let
. The if let
construct's only purpose is to make life easier in the case where you only want to destructure one pattern. If you want to destructure both cases of a Result
, you have to use match
(or multiple if let
or unwrap()
, but this is not a good solution). Why you don't want to use match
in the first place?
Regarding your compiler error: you added the Ok()
on the wrong side:
if let Ok(lines) = lines_from_file(filename) { ... }
This is the correct way of using if let
: the destructuring pattern to the left, the expression producing a value to the right.
Upvotes: 35