0

I am trying to get started with Rust, and wondered how the following piece of c++ code can be converted to rust.

Consider this C++ code:

void func(int c) {
  unordered_map<int, int> map;
  auto& a = map[10];
  auto& b = map[20];
  // some complex logic
  if (c > 10) {
    a += 1;
    b += 1;
  } else {
    a += 2;
    b += 2;
  }
  cout << map[10] << " " << map[20] << '\n';
}

Right now, I have replaced some complex logic with a simple if/else, but in essence, I need two mutable references to two values inside my hash map.

Consider the corresponding rust code:

fn func(c: i32) {
    let mut map = HashMap::new();
    let a = map.entry(&10).or_insert(0);
    let b = map.entry(&20).or_insert(0);
    // some complex code here
    if c > 10 {
        *a += 1;
        *b += 1;
    } else {
        *a += 2;
        *b += 2;
    }
}

rustc will not compile this code because I have two mutable references to map here.

How should one go about doing this in rust?

skgbanga
  • 2,477
  • 2
  • 20
  • 29
  • Do you need `a` and `b` in said complex code? If not, why not deal with them at the end, looking up and updating them in a single line? – ShadowRanger Apr 20 '21 at 04:31
  • 2
    Not a precise duplicate, but I suspect the answer to [Equivalent of split_at_mut for HashMap?](https://stackoverflow.com/q/64187018/364696) applies here (namely, as written, this isn't possible; you could take immutable borrows if you need `a`/`b` during complex code, you'd just have to wrap their declarations in a separate block so they're released before you perform the mutable updates at the end). – ShadowRanger Apr 20 '21 at 04:38

1 Answers1

2

You could try to use interior mutability pattern to achieve this goal, your code will change to something like this.

use std::collections::HashMap;
use std::cell::Cell;

fn func(c: i32) {
    let mut map = HashMap::new();
    map.insert(10, Cell::new(0));
    map.insert(20, Cell::new(0));
    
    let a = map.get(&10).unwrap();
    let b = map.get(&20).unwrap();
    // some complex code here
    if c > 10 {
        a.set(a.get() + 1);
        b.set(b.get() + 1);
    } else {
        a.set(a.get() + 2);
        b.set(b.get() + 2);
    }
}

Playground link

Inline
  • 2,566
  • 1
  • 16
  • 32