When lazy iterators don't iterate

There were several places in my (small) program where I was using iterators to go through things. However, I found that the iterators were iterating.
In one case, I was using an iterator to search for a name in a vactor, and extract the position and whether I found the name. As a for loop, easy. As an iterator (with the same body, just in a .map(|arg| ...), the iterator never called the map.
In the second case, I was using the iterator to:

    short.iter().map(|ls| {
            if !hm.contains_key(&ls.label) {
                hm.insert(ls.label.clone(), ls.strings.clone());
            } else {
                let mut v1 = hm.get(&ls.label).unwrap().clone();
                v1.extend(ls.strings.clone());
                hm.insert(ls.label.clone(), v1);
            }
    }

Where short is a vector of LabeledStrings (a structure containing a label (string) and a vector of strings). As a for loop, it does exactly what I want. As a .map, it does nothing. Okay. I will use the for loop. But I am clearly misunderstanding something about using iterators. Is the problem that I am copying everything and therefore not consuming the iterator?
Thanks for any explanations,
Joel

The problem is that map produces a new iterator that is itself meant to be used in some way. In your case that’s an iterator of () items, since the closure doesn’t return any value, but it’s an iterator nontheless.

If you just want to run a closure for each element of the iterator and then return nothing, simply use for_each instead of map :wink:

3 Likes

Thank you. for_each would do exactly what I was looking for in these cases.
I will say that the runtime failure from using .map is rather "interesting" to diagnose. But now I know.
Yours,
Joel

It should usually generate a warning though, if you don’t use an iterator produced by map.

By the way, you can probably simplify the code to something along the lines of

short.iter().for_each(|ls| {
    hm.entry(ls.label.clone())
        .or_default()
        .extend(ls.strings.iter().cloned());
});
1 Like