Luny
Luny

Reputation: 11

How to transform HashMap value in Rust

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));

Upvotes: 1

Views: 2390

Answers (2)

Jonathan Giddy
Jonathan Giddy

Reputation: 1801

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)
);

Upvotes: 4

Chayim Friedman
Chayim Friedman

Reputation: 70840

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),
);

Upvotes: 1

Related Questions