簡體   English   中英

Rust 無法將不同的結構插入 hashmap

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

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM