简体   繁体   English

当它是HashMap中的键时,是否可以修改可变向量?

[英]Is it possible to modify a mutable vector when it is a key in 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 actually modify 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 the HashMap owns the Vec , so I cannot modify it. 现在HashMap拥有Vec ,所以我无法修改它。

As far as I understand, you cannot modify a Vec if it is used as key in HashMap even though it is technically mutable. 据我所知,如果它被用作HashMap键,即使它在技术上是可变的,也无法修改Vec Is my understanding correct? 我的理解是否正确? Is there a trick or a corner case that I am missing? 我缺少一个技巧或角落案例吗?

No, you cannot modify it, and even if you could, you absolutely should never do such a thing. 不,你不能修改它,即使你可以,你绝对不应该做这样的事情。

In your example, the reason you cannot modify the vector is because you no longer own it . 在您的示例中,您无法修改向量的原因是因为您不再拥有它 You've transferred ownership of it to the map. 您已将其所有权转让给地图。 That's what "use of moved value" means. 这就是“使用移动价值”的意思。

Let's say you had some way of modifying the key of the map (I'm not going to provide any examples to help prevent people from doing this). 假设你有一些修改地图键的方法(我不打算提供任何例子来帮助阻止人们这样做)。 The main problem is that you'd be breaking an invariant of the HashMap : 主要问题是你要打破HashMap的不变量:

It is a logic error for a key to be modified in such a way that the key's hash, as determined by the Hash trait, or its equality, as determined by the Eq trait, changes while it is in the map. 以这样一种方式修改密钥是一个逻辑错误:密钥的哈希值由哈希特征确定,或由等式特征确定的等式,在它在地图中时发生变化。

The reason for this is simple once you understand how hashmaps work. 一旦了解了hashmaps的工作原理,这一点很简单。 When you add a key, an algorithm is run that converts the key into an integer (the key is hashed ). 添加密钥时,会运行一个算法,将密钥转换为整数(密钥经过哈希处理 )。 Then, this integer is used to find a space in an array to store the value. 然后,此整数用于查找数组中的空间以存储该值。

If you changed the key, then the value would be stored in the wrong spot in the array . 如果更改了密钥,则该值将存储在数组中的错误位置 As a simple example, imagine that the hashing algorithm for vectors was simply the number of items in the vector. 举一个简单的例子,假设向量的散列算法只是向量中的项目数。 If you added vec![1] as a key, it would be stored in array slot 1. If you then change the key, it should hash to 2, but would still be stored in slot 1! 如果你添加了vec![1]作为密钥,它将存储在数组插槽1中。如果你随后更改密钥,它应该散列为2,但仍然存储在插槽1中!

I am afraid this all stems from a misunderstanding about what mut means. 我担心这一切都源于对mut意味着什么的误解。

You need to distinguish two terms: 您需要区分两个术语:

  • vec![5, 6, 7] produces an instance of the Vec type vec![5, 6, 7]生成Vec类型的实例
  • my_vec is a binding , that is to say, a name given to an instance of a type, because it's easier to manipulate instances by name (but not necessary, cue Forth ) my_vec是一个绑定 ,也就是说,一个类型实例的名称,因为它更容易按名称操作实例(但不是必需的,提示Forth

When you declare let mut my_vec , you are: 当你声明let mut my_vec ,你是:

  • declaring a mutable binding 声明一个可变的绑定
  • to which an instance of Vec is bound Vec一个实例绑定Vec一个

The instance itself cannot be called mutable, it is meaningless as illustrated by the following valid snippet: 实例本身不能被称为可变,它是无意义的,如以下有效片段所示:

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

In this snippet, we see: 在这个片段中,我们看到:

  • an instance of Vec type being bound to a mutable binding my_vec Vec类型的实例绑定到可变绑定 my_vec
  • then being bound to an immutable binding other 然后绑定到一个不可变的绑定 other
  • then being bound to a mutable binding yac 然后被绑定到一个可变的结合 yac

which hopefully showcases that mutability is a property not of the instance but the binding . 希望能够证明可变性不是实例而是绑定的属性。

This is where inherited mutability comes into play: 这是继承的可变性发挥作用的地方:

  • If you are in possession of a mutable binding to an instance of T ( let mut x: T = ...; ), or binding to a mutable reference to an instance of T ( let x: &mut T = ...; ), then you can not only mutate its fields, but also obtain mutable references to these fields to modify their own fields... recursively. 如果你拥有对T 实例的可变绑定let mut x: T = ...; ),或者绑定到对T 实例的可变引用( let x: &mut T = ...; ) ,那么你不仅可以改变它的字段,还可以获得对这些字段的可变引用来递归地修改它们自己的字段。
  • And conversely, if all you hold is an immutable reference to an instance of type T ( let x: &T = ...; ), then all you can do is read its fields or obtain immutable references to these fields to read their own fields... recursively (*). 相反,如果你所持有的是对类型为T的实例的不可变引用( let x: &T = ...; ),那么你所能做的就是读取它的字段或获取对这些字段的不可变引用来读取它们自己的字段......递归地(*)。

(*) Ok, Ok, it's a simplification, the cell types for example can be modified via immutable references; (*)好的,好的,这是一个简化,例如可以通过不可变引用来修改cell类型; that's for another day! 那是另一天!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM