rust - 如何在不克隆的情况下获取对可变单例内部数据的引用?

标签 rust

我将Params结构存储到SERVICES单例中。使用get_params()函数,我得到了Params结构,但是我们必须克隆该结构的项才能使用它。

use lazy_static::lazy_static; // 1.4.0
use std::collections::HashMap;
use std::sync::Mutex;

#[derive(Debug)]
pub struct Params {
    pub verbose: bool,
    pub config_file: String,
}

lazy_static! {
    #[derive(Debug)]
    static ref SERVICES : Mutex<HashMap<&'static str, Params>> = Mutex::new( {
         HashMap::new()
    });
}

// OK
pub fn get_params() -> Params {
    let serv_map = &SERVICES.lock().unwrap();

    let cf: String = serv_map.get("params").unwrap().config_file.clone(); // clone here :(
    let verbose = serv_map.get("params").unwrap().verbose;

    Params {
        verbose,
        config_file: cf,
    }
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let params = Params {
        verbose: true,
        config_file: "/user/toto.yml".to_string(),
    };

    {
        SERVICES.lock().unwrap().insert("params", params);
    }

    let pp = get_params();

    if pp.verbose {
        dbg!(&pp.config_file, pp.verbose);
    }
    Ok(())
}

playground

我希望能够使用以下例程从单例中读取Params数据,而无需进行克隆:
/*
 Cannot compile
*/
pub fn get_params_ref<'lt>() -> &'lt Params {
    let serv_map: &'lt HashMap<&'static str, Params> = &SERVICES.lock().unwrap();

    let pp = &serv_map.get("params").unwrap();

    pp
}

我得到:

error[E0716]: temporary value dropped while borrowed
  --> src/main.rs:22:57
   |
21 | pub fn get_params_ref<'lt>() -> &'lt Params {
   |                       --- lifetime `'lt` defined here
22 |     let serv_map: &'lt HashMap<&'static str, Params> = &SERVICES.lock().unwrap();
   |                   ----------------------------------    ^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
   |                   |
   |                   type annotation requires that borrow lasts for `'lt`
...
27 | }
   | - temporary value is freed at the end of this statement

我知道为什么Rust无法编译此代码,但是有解决方案来获得对Params结构的不变引用吗?

最佳答案

如所写,您不能返回对SERVICES元素的引用,因为编译器不知道这些元素的生存期:代码的另一部分可能会删除服务!

假设您只向SERVICES添加元素,但从不删除任何元素,则因为它们是全局元素,所以可以对它们进行leak:

Params的定义更改为

#[derive(Debug)]
pub struct Params {
    pub verbose: bool,
    pub config_file: &'static str,
}

然后使用config_file初始化参数的Box::leak(String::from("foo").into_boxed_str())

程序关闭时,操作系统将回收泄漏的内存。

也可以看看:
  • How to convert a String into a &'static str
  • 关于rust - 如何在不克隆的情况下获取对可变单例内部数据的引用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60840948/

    相关文章:

    rust - 线程 'main' 在 Rust 中溢出了它的堆栈

    types - 返回一个类型,而不是一个实例

    rust - 为什么特质不能 self 构建?

    rust - 如何在v0.99.10中克隆async_std::path::PathBuf?

    rust - 函数指针的生命周期是 <'a, ' _> 而它应该是 <'r>

    rust - 为什么我在函数外部不需要的值会出现 "Borrowed value does not live long enough"错误?

    multithreading - 让 Rust 线​​程摆脱阻塞操作的标准方法是什么?

    rust - 为什么actix_rt可以直接在代码中使用,即使它没有声明?

    rust - 枚举变体的通用向下转型

    compiler-errors - 找到预期的 XYZ ()