2017-01-13 2 views
0

J'utilise lazy_static pour conserver un HashMap dans la mémoire. Avec deux méthodes, j'ajoute et j'obtiens des éléments, mais j'ai quelques problèmes avec les durées de vie.Problème de durée de vie avec une variable mutable lazy_static

Ceci est mon code:

#[macro_use] 
extern crate lazy_static; 

use std::sync::Mutex; 
use std::collections::HashMap; 

lazy_static! { 
    static ref HASHMAP: Mutex<HashMap<String, Foo>> = Mutex::new({ 
     let mut m = HashMap::new(); 
     m.insert("one".to_string(), Foo{param1:"foo1".to_string(), param2:"foo2".to_string()}); 
     m.insert("two".to_string(), Foo{param1:"bar1".to_string(), param2:"bar2".to_string()}); 
     m 
    }); 
} 

pub struct Foo{ 
    param1: String, 
    param2: String, 
} 

pub fn ins_val(name: String, f: Foo){ 
    HASHMAP.lock().unwrap().insert(name, f); 
} 

pub fn get_val(k: &str) -> Option<&Foo>{ 
    HASHMAP.lock().unwrap().get(k) 
} 

Et ceci est l'erreur:

HASHMAP.lock().unwrap().get(k) 
^^^^^^^^^^^^^^^^^^^^^^^ 
reference must be valid for the anonymous lifetime #1 defined on the block 

Répondre

9

Rust empêche correctement un bug ici.

Votre fonction get_val essaie de renvoyer une référence dans HASHMAP, mais ce n'est pas sûr à moins de continuer à tenir le verrou, car quelqu'un d'autre pourrait venir et modifier la carte sous vos pieds.

Vous devez soit garder le verrou jusqu'à ce que vous retournez la valeur (en retournant la garde de mutex ainsi que la valeur, par exemple en utilisant MutexGuardRef de la caisse owning_ref), ou copier la valeur au lieu de retourner une référence:

pub fn get_val(k: &str) -> Option<Foo> { 
    HASHMAP.lock().unwrap().get(k).cloned() 
} 

Avec cette implémentation, Foo aurait bien sûr besoin de mettre en œuvre Clone.

+0

Une autre option consiste à changer l'interface pour accepter une fermeture qui obtient une référence dans la carte, qui peut choisir de renvoyer une copie de la référence ou simplement de l'inspecter. Plus de détails [dans cette réponse] (http://stackoverflow.com/a/40853817/1600898). – user4815162342

+0

Notez que vous pouvez utiliser 'option.cloned()' comme raccourci pour 'option.map (Clone :: clone)'. – user4815162342

+1

Merci - mis à jour pour utiliser cloné. –