[英]Rust can't insert different structs into hashmap
假设我有一个结构,我想将 hash 放入 2 个HashMap
中,这样第一个拥有对它的引用,而第二个拥有它,就像这样:
struct Person { id: i32 }
fn main() -> std::io::Result<()> {
let mut first_name_table = HashMap::new();
let mut last_name_table = HashMap::new();
let person1 = Person { id: 1};
let first_name1 = "first1";
let last_name1 = "last1";
last_name_table.insert(last_name1, &person1);
first_name_table.insert(first_name1, person1);
Ok(())
}
这可以正常工作并且符合预期。 但是,当我尝试插入第二个人时,借阅检查器吓坏了:
struct Person { id: i32 }
fn main() -> std::io::Result<()> {
let mut first_name_table = HashMap::new();
let mut last_name_table = HashMap::new();
let person1 = Person { id: 1};
let first_name1 = "first1";
let last_name1 = "last1";
last_name_table.insert(last_name1, &person1);
first_name_table.insert(first_name1, person1);
let person2 = Person { id: 2};
let first_name2 = "first2";
let last_name2 = "last2";
last_name_table.insert(last_name2, &person2);
first_name_table.insert(first_name2, person2);
Ok(())
}
我得到的错误是:
error[E0505]: cannot move out of `person1` because it is borrowed
--> src/main.rs:20:42
|
19 | last_name_table.insert(last_name1, &person1);
| -------- borrow of `person1` occurs here
20 | first_name_table.insert(first_name1, person1);
| ^^^^^^^ move out of `person1` occurs here
...
26 | last_name_table.insert(last_name2, &person2);
| --------------- borrow later used here
但是第 26 行与person1
无关,为什么会这样呢?
当您将person1
移动到first_name_table
时,会使存储在last_name_table
中的引用&person1
无效,但是如果您不再使用last_name_table
则编译器会允许代码编译,但是一旦您尝试使用last_name_table
,编译就会抛出错误,因为它包含无效的引用. 尝试使用它的方式或时间都没有关系。 即使只是简单地删除它也会触发错误:
use std::collections::HashMap;
struct Person { id: i32 }
fn main() -> std::io::Result<()> {
let mut first_name_table = HashMap::new();
let mut last_name_table = HashMap::new();
let person1 = Person { id: 1};
let first_name1 = "first1";
let last_name1 = "last1";
last_name_table.insert(last_name1, &person1);
first_name_table.insert(first_name1, person1);
drop(last_name_table); // triggers error
Ok(())
}
考虑到您存储对该人的引用然后立即移动它,我对第一个版本完全编译感到惊讶。 我猜编译器可以看到在该点之后没有使用引用(编辑:这是因为地图的Drop
实现中的#[may_dangle]
)。 无论如何,它不是第二次插入,但任何使用last_name_table
都会触发错误:
let mut first_name_table = HashMap::new();
let mut last_name_table = HashMap::new();
let person1 = Person { id: 1};
let first_name1 = "first1";
let last_name1 = "last1";
last_name_table.insert(last_name1, &person1);
first_name_table.insert(first_name1, person1);
println!("{:?}", last_name_table);
error[E0505]: cannot move out of `person1` because it is borrowed
--> src/main.rs:15:42
|
14 | last_name_table.insert(last_name1, &person1);
| -------- borrow of `person1` occurs here
15 | first_name_table.insert(first_name1, person1);
| ^^^^^^^ move out of `person1` occurs here
16 |
17 | println!("{:?}", last_name_table);
| --------------- borrow later used here
您可以尝试将其插入其中,然后获取参考以避免移动问题:
let person1_ref = first_name_table.entry(first_name1).or_insert(person1);
last_name_table.insert(last_name1, person1_ref);
但这不会让您再修改first_name_table
,因为last_name_table
是不可变地引用它。 几乎对 hash 地图的任何操作都可能最终移动现有元素,这意味着引用将变得无效。 Rust 会阻止你这样做。
解决方法是清除您的所有权 model。 我建议使用Rc
以便每个 map共享此人的所有权。 看到它在操场上工作:
let mut first_name_table = HashMap::new();
let mut last_name_table = HashMap::new();
let person1 = Rc::new(Person { id: 1});
let first_name1 = "first1";
let last_name1 = "last1";
last_name_table.insert(last_name1, Rc::clone(&person1));
first_name_table.insert(first_name1, person1);
let person2 = Rc::new(Person { id: 2});
let first_name2 = "first2";
let last_name2 = "last2";
last_name_table.insert(last_name2, Rc::clone(&person2));
first_name_table.insert(first_name2, person2);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.