[英]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.