在这个最小的可重现示例中,我们有一个哈希映射,其值包含
Vec<i32
,据我所知,Vec<T>
没有实现 Copy
,因此它将在需要时随时移动。
use std::collections::HashMap;
#[derive(Clone)]
struct MyStruct {
id: i32,
vec_number: Vec<i32>,
}
fn main() {
let mut hashmap: HashMap<i32, Vec<i32>> = HashMap::new();
let a = MyStruct {
id: 1,
vec_number: vec![1, 2, 3],
};
let b = MyStruct {
id: 2,
vec_number: vec![1, 2, 3],
};
let first_vec = vec![a, b];
for strct in first_vec {
hashmap.insert(strct.id, strct.vec_number);
}
let second_vec : Vec<i32> = *hashmap.get(&2).unwrap(); // error here
}
我得到的错误是:
cannot move out of a shared reference
move occurs because value has type `Vec<i32>`, which does not implement the `Copy` trait
我理解说
Vec<T>
从 hashmap
将移至 second_vec
(“移出共享引用”部分)的部分。但是,我不明白的是:为什么这是一个错误,因为我不会再在范围内使用 hashmap
?根据我的理解,只有当我在代码中的其他地方引用移动的值时,此移动才会出现问题。
我听说它是强制用户使用
remove()
,它的作用与上面的代码相同,但是以更惯用的方式(因为我们不必取消引用该值,就像 hashmap.get()
发生的那样)
)。
这是真的吗?这种行为的原因是什么?
Rust 是一种强类型语言,这是一种设计决策,旨在防止人们做出导致未定义行为或安全代码中内存不安全的事情。
其中一部分是所有权:当您拥有
T
时,您拥有它并且可以随心所欲地使用它,但是当您拥有 &T
时,那么您只是借用它,其他人拥有它。
当您使用
get
方法时,您仅获得一个引用,因此,您无法移动底层 T
(在本例中为 Vec<i32>
)。如果它是 Copy
,而 Vec<i32>
不是,您可以轻松地将其复制到新的 T
中,但否则,即使引用的所有者即将离开,您也无法移出引用。如果您有 &mut T
,则可以移出引用,前提是您将其替换为其他内容,例如使用 std::mem::take
,但不可变引用是不可变的。
这样做的原因是,这会产生简单、易于推理的行为,并且实现起来简单且高效。它还允许人们编写代码,例如防止从集合中删除项目,这在某些情况下可能是理想的。
如果您想从旧
HashMap
获得该项目的所有权,那么您必须先将其删除。