Heya peeps,
While working on today's advent of code, I found myself with a question regarding the chaining of map calls when each mapped function returns a Result.
I have the following code:
pub fn sum_of_badge_priorities(&self) -> Result<u32, &'static str> {
self.0
.iter()
.map(|group| group.find_badge().and_then(Rucksack::priority))
.sum()
}
For context, I have a vector of groups, each group contains a badge, each badge can have a priority calculated on it. The goal of this function is to return the sum of the priorities of each badge in the groups.
Of course, the Group::find_badge
and Rucksack::priority
functions can fail, e.g. because there is no badge or because the badge is invalid and cannot be assigned a priority. In case of failure, nothing should be calculated and the whole function should return the appropriate Err
.
This code works, but out of curiosity I tried to separate the complicated map into two successive maps, like so:
pub fn sum_of_badge_priorities(&self) -> Result<u32, &'static str> {
self.0
.iter()
.map(Group::find_badge)
.map(Rucksack::priority)
.sum()
}
Of course, this code fails, since I give a Result<Badge>
to Rucksack::priority
. I could make the code compile by transforming the first map into a flat_map, but the behavior is subtly different: in one case of error, the group will be silently discarded, and sum will work on a empty iterator, returning Ok(0)
.
Basically, I'm wondering if there is a sort of bind operator for iterators, some kind of super and_then
that will behave like the first code snippet. I didn't find any try_map
method, but some discussion explaining while this function would need to eagerly evaluate as the reason for its non-existence. I also found the very helpful Iterating over Results page, but it doesn't address the case of chaining multiple maps.
I guess this is also a question about style and idiomatic Rust: in this kind of scenario, what would be the most idiomatic? Having a "big" map that does all the computation or chaining different maps? (Of course there's simply the possibility of extracting that function composition into its own function and map over it, but this is just for fun).
Cheers!