Iterating over Results

#1

Hi all,
I just wrote up this blog post on iterating over Results: https://lliwynd.blogspot.com/2019/01/iterating-over-results-in-rust.html . Is it possible to simplify the final version any more?

Thanks,

Will :-}

1 Like
#2

.map() followed by .try_fold() seems redundant, since you can put the map closure body inside the try_fold closure (although I’m not loving what rustfmt did with the following):

let sum: i64 = buffered.lines().try_fold(0, |acc, r| {
    r.map_err(Box::<dyn std::error::Error>::from)
        .and_then(|s| s.parse::<i64>().map_err(|e| e.into()))
        .map(|y| acc + y)
})?;

I made other changes, but you don’t need to agree with them: passing Box::<dyn Error>::from to map_err instead of annotating it with a type, and turning the second .and_then into a simple .map.

I’d probably write the for loop though. You want the Results to affect control flow in the current function; it only makes sense to write in an imperative style to take advantage of ?.

1 Like
#3

Thanks for taking a look.

I prefer having the map before the fold. I prefer having the textual order match the order of operations we want. The second and_then being a simple map is an improvement though.

I was hoping there was a way to get rid of the second map_err. But I guess you’re right, if you’re going to be imperative about it then you’re better off with the imperative syntax.

#4

Yes, I agree with @trentj, I’d just like to strain the newer syntax mentioned dyn Trait as opposed to Trait which is the new syntax, so I can only presume that at some point it will be deprecated.

#5

Here’s another… slightly(?) ugly way to do it by specifying the closure return type on try_fold.

let sum: i64 = buffered
    .lines()
    .try_fold::<_, _, Result<_, Box<dyn Error>>>(0, |acc, r| Ok(r?.parse::<i64>()? + acc))?;

I still think I’d go with the for loop.

#6

That certainly makes things nicer. You get to use the try/? operator much more.

Why can’t that type constraint on try_fold be inferred?