[英]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
,你是:
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: 在这个片段中,我们看到:
Vec
type being bound to a mutable binding my_vec
Vec
类型的实例绑定到可变绑定 my_vec
other
other
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: 这是继承的可变性发挥作用的地方:
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 = ...;
) ,那么你不仅可以改变它的字段,还可以获得对这些字段的可变引用来递归地修改它们自己的字段。 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.