繁体   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