Want to add to HashMap using pattern match, get borrow mutable more than once at a time

爷,独闯天下 提交于 2019-12-01 15:03:57

You have to use the Entry "pattern":

use std::collections::HashMap;
use std::collections::hash_map::Entry::{Occupied, Vacant};

fn main() {
    let mut words = vec!["word1".to_string(), "word2".to_string(), "word1".to_string(), "word3".to_string()];
    let mut wordCount = HashMap::<String, u32>::new();

    for w in words {
        let val = match wordCount.entry(w) {
           Vacant(entry) => entry.insert(0),
           Occupied(entry) => entry.into_mut(),
        };

        // do stuff with the value
        *val += 1;
    }

    for k in wordCount.iter() {
        println!("{:?}", k);
    }
}

The Entry object allows you to insert a value if its missing, or to modify it if it already exists.

https://doc.rust-lang.org/stable/std/collections/hash_map/enum.Entry.html

A.B.

HashMap::entry() is the method to use here. In most cases you want to use with Entry::or_insert() to insert a value:

for word in line.split(" ") {
    *c.entry(word).or_insert(0) += 1;
}

In case the value to be inserted need to be expensively calculated, you can use Entry::or_insert_with() to make sure the computation is only executed when it needs to. Both or_insert methods will probably cover all of your needs. But if you, for whatever reason, want to do something else, you can still simply match on the Entry enum.

Lukas Kalbertodt

This is basically not an issue anymore. With non-lexical lifetimes (NLL), your code compiles without problems. Your example on the Playground.

NLL is a new way the compiler reasons about borrows. NLL has been enabled in Rust 2018 (≥ 1.31). It is planned to be enabled in Rust 2015 eventually as well. You can read more about NLL and editions in this official blog post.

In this particular case, I still think A.B.'s answer (entry(word).or_insert(0)) is the best solution, simply because it is very concise.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!