Is it possible to change a mutable vector when it is a key in a HashMap?

Here is my example:

use std::collections::HashMap; fn main() { let mut my_map = HashMap::new(); let mut my_vec = vec![5,6,7]; my_map.insert(my_vec, 4); // This part is fine, so I can create HashMap // with mutable Vector as key. my_vec.push(8); } 

However, I cannot change the vector! my_vec.push(8); causes the following error:

 post_test_19.rs:14:5: 14:11 error: use of moved value: `my_vec` [E0382] post_test_19.rs:14 my_vec.push(8); ^~~~~~ post_test_19.rs:7:19: 7:25 note: `my_vec` moved here because it has type `collections::vec::Vec<i32>`, which is non-copyable post_test_19.rs:7 my_map.insert(my_vec, 4); ^~~~~~ error: aborting due to previous error 

Now HashMap owns Vec , so I can’t change it.

As far as I understand, you cannot change Vec if it is used as a key in HashMap , even if it is technically changed. Do I understand correctly? Is there a trick or corner case that I am missing?

+4
source share
2 answers

No, you cannot change it, and even if you could, you should absolutely not do anything.

In your example, the reason you cannot change the vector is because you no longer own it. You transferred ownership of it to the card. That which means "using the moved value".

Let's say you had some way to change the card key (I'm not going to give any examples to help people do this). The main problem is that you are breaking the HashMap invariant:

This is a logical mistake for the key to be modified in such a way that the hash of the key defined by the Hash trait, or its equality, determined by the Eq attribute, changes when it is on the map.

The reason for this is simple if you understand how hashmaps work. When you add the key, an algorithm is launched that converts the key to an integer (the key is hashed). This integer is then used to find the space in the array to store the value.

If you changed the key, then the value will be stored in the wrong place in the array. As a simple example, suppose the vector hashing algorithm was just the number of elements in the vector. If you added vec![1] as the key, it will be saved in array slot 1. If you then change the key, it should be set to 2, but it will still be stored in slot 1!

+5
source

I am afraid that all this stems from a misunderstanding of what mut means.

You need to distinguish between two terms:

  • vec![5, 6, 7] creates an instance of type Vec
  • my_vec is the binding, that is, the name given to the type instance, because it is easier to manipulate the instances by name (but not necessarily, cue Forth )

When you declare let mut my_vec , you:

  • Variable Binding Declaration
  • to which the Vec instance is bound

The instance itself cannot be called mutable, it is pointless, as shown in the following valid fragment:

 let mut my_vec = vec![5, 6, 7]; let other = my_vec; // ownership transfer let mut yac = other; // ownership transfer 

In this fragment we see:

  • Vec instance bound to my_vec mutable binding
  • and then bound to the immutable binding of other
  • and then yac mutable binding

which, we hope, will demonstrate that volatility is not a property of an instance, but a binding.

Inherited variability comes into play here:

  • If you have a mutable binding to an instance of T ( let mut x: T = ...; ) or a binding to a mutable reference to an instance of T ( let x: &mut T = ...; ), then you can not only mutate its fields but also get mutable links to these fields to change their own fields ... recursively.
  • Conversely, if all you hold is an invariable reference to an instance of type T ( let x: &T = ...; ), then all you can do is read its fields or get immutable references to these fields so that read their own fields ... recursively (*).

(*) Well, Ok, this is a simplification, cell types, for example, can be changed using immutable links; what the next day!

+4
source

All Articles