Is having a HashMap with enum values a bad idea?

#1

I’d like to store a few different varieties in a hashmap, and a map of enums seemed like a brilliant idiomatic Rust-y solution.

However, when I started using it, I discovered that I can’t manipulate the enum values very easily because matching on the entry value either moves or locks the entry so I can’t update it.

I made a small failing example:

https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=0375e29a363fc30d8056abe37eb37b39

My goal around line 44 is, “If the entry value is a Choice::A, then replace the entry with a Choice::B”. I’d have similar cases for the other choices.

I feel like there a way this could be extremely elegant in Rust. Even the nested match statements suggest that I’m way off on something. But I can’t tell if it’s my code, the fact that I’m putting enums in a map, or something unrelated. Hints much welcome!

#2

You can probably improve things a bit with hash_map::Entry's and_modify and or_insert methods. The Choice enum part is a bit trickier since you don’t have Copy or Clone implemented, but if you add one you can do this: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=bfd70d0dc12855efaef633efb8c77435

If you don’t want to clone Choices then you will probably need to split the and_modify part into two phases- determining that you have a Choice::A and reading the old item out, and then inserting the new Choice::B.

1 Like
#3

For in place modification the best thing is to use get_mut() since by giving a &mut Choice handle you can overwrite in-place, without requiring key cloning or the suboptimal remove() -> insert().

The subtle thing is that you want to extract an Item from a &mut Choice::A. In your example the best is using Copy. When that isn’t possible, then mem::replace (or even better: Option::take) should do the trick.

1 Like