最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

dictionary - How to increment a counter in a map and get the current count - Stack Overflow

programmeradmin6浏览0评论

Can I do this in one expression?

*map.entry(key).or_default() += 1;
let count = *map.get(&key).unwrap();

Ideally, I would like this to be an atomic operation, but I can lock if needed.

/?version=stable&mode=debug&edition=2021&gist=df6778cd1312c31eb230a545c6c2b6ce

Can I do this in one expression?

*map.entry(key).or_default() += 1;
let count = *map.get(&key).unwrap();

Ideally, I would like this to be an atomic operation, but I can lock if needed.

https://play.rust-lang./?version=stable&mode=debug&edition=2021&gist=df6778cd1312c31eb230a545c6c2b6ce

Share Improve this question edited Jan 17 at 15:49 fadedbee asked Jan 17 at 15:27 fadedbeefadedbee 44.8k48 gold badges199 silver badges351 bronze badges 5
  • 3 Post a minimal reproducible example. It is not clear what types we are talking about here. – Eugene Sh. Commented Jan 17 at 15:33
  • @EugeneSh. I've added a Rust Playground link. – fadedbee Commented Jan 17 at 15:52
  • 1 Can you clarify what you mean by "an atomic operation"? Are you just focused on a single expression? Or just avoiding the second key lookup? Or is your map really synchronized with other threads and needs the change to appear atomic? I ask because you mention "atomic"s and "lock"s but you've accepted an answer that doesn't address those (at least not in the normal - i.e. threading - sense) – kmdreko Commented Jan 17 at 18:58
  • I believe that by “atomic” OP means a single line and a single lookup, not in the sense of concurrency/thread-safety. – BallpointBen Commented Jan 18 at 15:56
  • @BallpointBen I meant atomic as in being called from multiple threads, yielding a convergent result regardless of ordering. I hadn't thought it through though, as that would require a lock-free Map - i.e. the map-lookup/insert and counter-increment would both need to be atomic in combination, which is probably beyond what can be achieved with atomics. – fadedbee Commented Jan 20 at 7:49
Add a comment  | 

2 Answers 2

Reset to default 2

You can:

let count = *map.entry(key).and_modify(|v| *v += 1).or_insert(1);

This will:

  • Get or create the entry
  • If it exists, increment it
  • If it doesn't exist, insert 1
  • Return a reference to the value, which we then dereference

I don't know if you consider the following initialisation of count as only one expression, but at least it avoids a second lookup with .get().
I suppose the atomic operation is on the integer, not the whole map (maybe I'm wrong).

fn main() {
    let mut map = std::collections::HashMap::new();
    map.insert(String::from("a"), std::sync::atomic::AtomicUsize::new(100));
    //
    for k in ["a", "b"] {
        let key = String::from(k);
        let count = map
            .entry(key)
            .or_default()
            .fetch_add(1, std::sync::atomic::Ordering::Relaxed)
            + 1;
        println!("{} ~~> {}", k, count)
    }
    //
    println!("{:?}", map);
}
/*
a ~~> 101
b ~~> 1
{"a": 101, "b": 1}
*/
发布评论

评论列表(0)

  1. 暂无评论