Как получить ссылку на данные внутри изменяемого синглтона без клонирования? - PullRequest
0 голосов
/ 25 марта 2020

Я сохраняю структуру 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(())
}

детская площадка

Я бы хотел иметь возможность читать данные 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?

1 Ответ

2 голосов
/ 25 марта 2020

Как написано, вы не можете возвращать ссылки на элементы SERVICES, потому что компилятор не знает, как долго они будут жить: другая часть вашего кода может удалить службу!

Предполагая, что вы только когда-либо добавить элементов к SERVICES, но никогда удалить любых элементов, тогда, поскольку они глобальные, можно утечка их:

Изменить определение Params до

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

И инициализируйте ваши параметры 'config_file, используя Box::leak(String::from("foo").into_boxed_str()).

Утечка памяти будет возвращена вашей ОС, когда ваша программа закроется.

Смотрите также:

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...