1

I have a HashMap with key = id, value = Status; Now I want to update the status, but I have to remove and insert, because the new status is created from the old status. Is there any way to update without remove and insert?

enum Status {
    InCompleted(HashSet<WorkerId>),
    Working(WorkerId, HashSet<WorkerId>),
    Completed,
}
impl Status {
    fn to_working(self, worker_id: WorkerId) -> Self {
        match self {
            Self::InCompleted(w) => Self::Working(worker_id, w),
            _ => self,
        }
    }
// remove and insert new
let old_status = h.remove(&id).unwrap();
h.insert(id, old_status.to_working(cur_worker));
Stefan Zobel
  • 3,182
  • 7
  • 28
  • 38
Luny
  • 11
  • 2
  • 1
    If you change the `Value` type of the map to `Option`, that would be easy. If not, think of what would happen if your `to_working()` panics, what would the state of the map be? – rodrigo Feb 19 '22 at 13:58
  • Does this answer your question? [How can I update a value in a mutable HashMap?](https://stackoverflow.com/questions/30414424/how-can-i-update-a-value-in-a-mutable-hashmap) – Jonathan Feenstra Feb 19 '22 at 15:13

2 Answers2

4

Check out the entry method for HashMap, and its and_modify method: https://doc.rust-lang.org/std/collections/hash_map/enum.Entry.html#method.and_modify.

You can have something like:

h.entry(&id).and_modify(|status| 
    *status = status.to_working(cur_worker)
);
spdrman
  • 1,372
  • 2
  • 13
  • 18
Jonathan Giddy
  • 1,435
  • 10
  • 6
1

This is nothing that is exactly the same, unfortunately, but you can avoid looking up the value twice by replacing with the default, then inserting the new value. Note that it requires T: Default. If it is not, use a sensible default value (it'll stay there if the transformation will panic)

let status = h.get_mut(&id).unwrap();
let old_status = std::mem::take(status);
*status = old_status.to_working(cur_worker);

You can use a crate like replace_with:

replace_with::replace_with_or_default(
    h.get_mut(&id).unwrap(),
    |old_status| old_status.to_working(cur_worker),
);
Chayim Friedman
  • 47,971
  • 5
  • 48
  • 77