Mikko Rantalainen
Mikko Rantalainen

Reputation: 16015

How to immediately early return when Iterator gives error Result in a loop?

I'm in progress of learning Rust and I'm trying to apply similar style I'm using with C++. With C++ I would be using RAII and exceptions and the closest I can get with Rust is RAII combined with early return with error Result. As such, when I write code such as

fn parse_meminfo() -> Result<Meminfo, io::Error> {
  // ...
  let file = File::open("/proc/meminfo")?;
  for line in io::BufReader::new(file).lines() {
    let line = line?;
    // ...

Is it possible to somehow avoid the fragment let line = line?; of code? I already tried

for line in io::BufReader::new(file).lines()?

and

for line? in io::BufReader::new(file).lines()

and

for Ok(line) in io::BufReader::new(file).lines()

and

for line in io::BufReader::new(file).lines().expect("failed to read line")

but rustc wasn't happy with any of those. First and fourth have the test in logically wrong position because ? and expect() are testing the iterator instead of the item, if I've understood correctly. Second was syntax error, and the syntax Ok(line) is not happy to ignore the error because that doesn't mean early return. I would like to have early return with the error if the iterator in the loop gives an error and adding one extra line of code just for that seems silly and that test seems a bit detached from the actual loop. Can you suggest anything better? If the let line = line?; is indeed the idiomatic style, then I guess I would have to learn to love it.

Upvotes: 0

Views: 1425

Answers (1)

Masklinn
Masklinn

Reputation: 42472

Is it possible to somehow avoid the fragment let line = line?; of code?

Depending how you're using line, you could just tack on the ? over there. expr? simply desugars to1

match expr {
    Ok(v) => v,
    Err(e) => return e.into()
}

So you can see how the second attempt would not work (the left hand side of the for...in is an irrefutable pattern, not an expression).

The error handling here is largely orthogonal to the iteration, and iteration doesn't (at this juncture, though it seems unlikely that'll be added) have first-class support for error signaling, so you have an Iterator<Item=Result<...>> and you handle the Result however you wish.

If you don't care for the error reporting you could always .lines().map(|v| v.expect(...) and that'll immediately panic at the first error, but I don't know that that's what you're looking for.


1: that's not quite true anymore because of the `Try` trait, but close enough still

Upvotes: 2

Related Questions