`fold` values into a HashMap

After reading this article Learning Programming Concepts by Jumping in at the Deep End I can't seem to understand how exactly fold() is working in this context. Mainly how fold() knows to grab the word variable from split().

Here's the example:

use std::collections::HashMap;

fn count_words(text: &str) -> HashMap<&str, usize> {
    text.split(' ').fold(
        HashMap::new(),
        |mut map, word| { *map.entry(word).or_insert(0) += 1; map }
    )
}

Playground

Rust docs say:

fold() takes two arguments: an initial value, and a closure with two arguments: an ‘accumulator’, and an element. The closure returns the value that the accumulator should have for the next iteration.

Iterator - fold

So I get the mut map is the accumulator and I get that split() returns an iterator and therefore fold() is iterating over those values but how does fold know to grab that value? It's being implicitly passed but I cant seem to wrap my head around this. How is that being mapped to the word variable...

Not sure if I have the right mental model for this...

Thanks!


Solution 1:

but how does fold know to grab that value?

fold() is a method on the iterator. That means that it has access to self which is the actual iterator, so it can call self.next() to get the next item (in this case the word, since self is of type Split, so its next() does get the next word). You could imagine fold() being implemented with the following pseudocode:

fn fold<B, F>(mut self, init: B, mut f: F) -> B
where
    Self: Sized,
    F: FnMut(B, Self::Item) -> B,
{
    let mut accum = init;
    while let Some(x) = self.next() {
        accum = f(accum, x);
    }
    accum
}

Ok, the above is not pseudocode, it's the actual implementation.