使用 HashMap 引用作为值的 HashMap 的生命周期问题

Lifetime problem with HashMap with HashMap references as values

(生锈新手,仅供参考!)

所以 - 我一直在努力理解 Rust 中生命周期的概念。我已经阅读了文档,并阅读了一些关于该主题的博客和 SO posts。但仍然完全明白(因此,问题的标题可能不好)。

我有一个特别的问题想弄清楚,我已经将其归结为这个小示例代码(试图尽可能接近工作示例):

use std::collections::HashMap;

// Imagine this is actually a more complex type:
type BigComplexType = i32;

fn some_expensive_computation() -> BigComplexType {
    // Imagine this takes some arguments, and takes a long time to run
    return 123;
}

fn construct() -> HashMap<i32, &'static HashMap<i32, BigComplexType>> {
    let mut main = HashMap::new();

    let mut nested = HashMap::new();
    nested.insert(1111, some_expensive_computation());
    nested.insert(2222, some_expensive_computation());
    // ... and lots more inserts...

    main.insert(10, &nested);
    main.insert(20, &nested);
    // ... and lots more inserts...

    // Imagine a lot more other nested HashMaps to follow here
    // let mut nested2 = ...
    // ...
    // main.insert(..., &nested2);
    // ...

    return main;
}


fn main() {
    construct();
}

这个例子有点琐碎 - 在实际代码中,我在 construct() 函数中创建了更复杂、更深入的结构。

我想做的是创建某种缓存来保存这些 pre-computed 值,以便可以在代码中的其他地方轻松快速地访问它们。也许这一切都可以通过一些完全不同的方式来完成 - 但我认为必须有一种方法可以做到这一点。

但是,rustc这里就报错了,因为nested只存在于construct(),一旦我们脱离了这个函数,它就不存在了,所以所有的引用都是无效(或者,这就是我对问题的理解)。

我尝试将 'a 生命周期引入 construct() 函数,并在下面的 nested HashMap 上使用该生命周期,但没有骰子。出现了一些错误,并且永远无法完全使其正常工作。我已经尝试了各种添加生命周期注释的变体,但没有成功。

我有一种感觉,我只是没有理解这里整个概念的某些方面。谁能帮我指明正确的方向?

(我确实考虑过将 nested HashMap 收集到一个向量中并与 main hashmap 一起返回 - 这样函数就会返回主 HashMap,加上嵌套的向量那些 - 因此,生命周期将得到保证,我 认为 - 但我尝试这样做时遇到了其他一些障碍,并且感觉我是 over-complicating 东西。)

供参考,这是我在编译上面得到的错误:

error[E0515]: cannot return value referencing local variable `nested`
  --> lifetime_return.rs:29:12
   |
19 |     main.insert(10, &nested);
   |                     ------- `nested` is borrowed here
...
29 |     return main;
   |            ^^^^ returns a value referencing data owned by the current function

error[E0515]: cannot return value referencing local variable `nested`
  --> lifetime_return.rs:29:12
   |
20 |     main.insert(20, &nested);
   |                     ------- `nested` is borrowed here
...
29 |     return main;
   |            ^^^^ returns a value referencing data owned by the current function

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0515`.

Any/all 帮助将不胜感激!我试图寻找类似的问题,但找不到一个 - 也许我只是没有将某些 SO post 识别为重复项,因为我还没有完全理解生命周期模型。

你对为什么这不起作用的直觉是正确的:nested 只存在于 construct 中,你尝试 return 在 hashmap 中对它的引用更长时间比功能。假设您不想克隆嵌套地图,大概是因为它们非常大,您可以使用 Rc 作为一种方式来对嵌套地图进行简单的可克隆引用,使它们在必要的:

use std::collections::HashMap;
use std::rc::Rc;

type BigComplexType = i32;

fn some_expensive_computation() -> BigComplexType {
    return 123;
}

fn construct() -> HashMap<i32, Rc<HashMap<i32, BigComplexType>>> {
    let mut main = HashMap::new();

    let mut nested = HashMap::new();
    nested.insert(1111, some_expensive_computation());
    nested.insert(2222, some_expensive_computation());

    let nested_rc = Rc::new(nested);
    main.insert(10, Rc::clone(&nested_rc));
    main.insert(20, nested_rc); // can move the Rc for the last insert
    
    let mut nested2 = HashMap::new();
    nested2.insert(3333, some_expensive_computation());
    nested2.insert(4444, some_expensive_computation());
    
    let nested2_rc = Rc::new(nested2);
    main.insert(30, Rc::clone(&nested2_rc));
    main.insert(40, nested2_rc);

    return main;
}


fn main() {
    let map = construct();
    println!("{}", map[&10][&1111]); // 123
}

Playground link