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

时间:2015-08-23 02:35:22

标签: rust

以下是我的例子:

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

但是,我实际上无法修改矢量! my_vec.push(8);导致以下错误:

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

现在HashMap拥有Vec,所以我无法修改它。

据我了解,如果在Vec中将HashMap用作密钥,则无法修改+layer,即使它在技术上是可变的。我的理解是否正确?我缺少一个技巧或角落案例吗?

2 个答案:

答案 0 :(得分:5)

不,你不能修改它,即使你可以,你绝对不应该做这样的事情。

在您的示例中,您无法修改向量的原因是您不再拥有它。您已将其所有权转让给地图。这就是“使用移动价值”的意思。

假设您有某种方法可以修改地图的关键字(我不会提供任何示例来帮助阻止人们这样做)。主要问题是你要打破HashMap

的不变量
  

修改密钥是一个逻辑错误,使得由Hash特征确定的密钥散列或其等式(由Eq特征确定)在映射中发生变化。 / p>

一旦了解了hashmaps的工作原理,这一点很简单。添加密钥时,会运行一个算法,将密钥转换为整数(密钥为哈希)。然后,该整数用于在数组中查找存储值的空间。

如果更改了密钥,则该值将存储在数组中的错误位置。举一个简单的例子,假设向量的散列算法只是向量中的项目数。如果您添加vec![1]作为密钥,它将存储在数组插槽1中。如果您随后更改密钥,散列为2,但仍将存储在插槽1中!

答案 1 :(得分:4)

我担心这一切都源于对mut的含义的误解。

您需要区分两个术语:

  • vec![5, 6, 7]生成Vec类型的实例
  • my_vec是一个绑定,也就是说,是一个类型实例的名称,因为它更容易按名称操作实例(但不是必需的,cue {{ 3}})

当您声明let mut my_vec时,您是:

  • 声明一个可变的绑定
  • Vec实例绑定

实例本身不能被称为可变,如下面的有效片段所示,它没有意义:

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

在此代码段中,我们看到:

  • Vec类型的实例绑定到可变绑定 my_vec
  • 然后绑定到不可变的绑定 other
  • 然后绑定到可变绑定 yac

希望展示可变性不是实例的属性,而是绑定

这是继承的可变性发挥作用的地方:

  • 如果您拥有{{1>}(T)的实例的可变绑定,或绑定到可变引用let mut x: T = ...;T)的实例,那么您不仅可以改变其字段,还可以获取对这些字段的可变引用,以递归方式修改自己的字段。
  • 相反,如果您所持有的是对let x: &mut T = ...;T)类型的实例的不可变引用,那么您所能做的就是读取其字段或获取对这些字段的不可变引用以进行读取他们自己的领域......递归地(*)。

(*)好的,好的,这是一个简化,例如let x: &T = ...;类型可以通过不可变引用修改;那是另一天!