使用折叠迭代器方法在 Rust 中创建 HashMap

Creating a HashMap in Rust using the fold iterator method

我正在尝试使用 Entry 和 Rust 中的迭代器从一组单词创建一个单词计数 HashMap。当我尝试如下时,

use std::collections::HashMap;
fn main () {
    let corpus = ["foo", "bar", "bar", "grok", "blah", "foo", "bar"];
    let mut word_count = corpus.iter().fold(HashMap::new(), |mut acc, word| *acc.entry(word).or_insert(0) += 1);
    println!("{:?}", word_count);
}

我收到错误:预期结构 HashMap,找到 (),类型不匹配

我可以通过创建一个新范围并显式返回累加器来让它工作:

use std::collections::HashMap;
fn main () {
    let corpus = ["foo", "bar", "bar", "grok", "blah", "foo", "bar"];
    let mut word_count = corpus.iter().fold(HashMap::new(), |mut acc, word|{
        *acc.entry(word).or_insert(0) += 1;
        acc
    });
    println!("{:?}", word_count);
}

我得到了预期的 {"foo": 2, "bar": 3, "blah": 1, "grok": 1}

通常 fold returns 累加器的最后状态,所以我期待第一种方法起作用,但不清楚为什么它不起作用。非常感谢对替代方法(使用迭代器)的一些说明和任何建议。

就像@PitaJ 的评论中解释的那样,*acc.entry(word).or_insert(0) += 1 具有类型 (),而编译器每次都期望 fold() 回调到 return 下一个状态(有时在其他语言中称为 reduce(),例如 JavaScript;在 Rust 中;fold() 允许您指定起始值,而 reduce() 从迭代器).

正因为如此,我觉得它更适合循环的用例,因为你不需要 return 一个新的状态,而是更新地图:

let mut word_count = HashMap::new();
for word in &corpus {
    *word_count.entry(word).or_insert(0) += 1;
}

Playground.

但是,如果您愿意,itertools 箱子中有一个方法可以做到这一点:counts():

let word_count = corpus.iter().counts();

Playground.