Come posso prendere in prestito un RefCell , trovare una chiave e restituire un riferimento al risultato?

Ho un RefCell e voglio prendere in prestito la tabella, trovare una chiave e restituire un riferimento al risultato:

 use std::cell::RefCell; use std::collections::HashMap; struct Frame { map: RefCell<HashMap>, } impl Frame { fn new() -> Frame { Frame { map: RefCell::new(HashMap::new()), } } fn lookup(&'a self, k: &String) -> Option { self.map.borrow().get(k) } } fn main() { let f = Frame::new(); println!("{}", f.lookup(&"hello".to_string()).expect("blargh!")); } 

( parco giochi )

Se rimuovo RefCell allora tutto funziona bene:

 struct Frame { map: HashMap, } impl Frame { fn lookup(&'a self, k: &String) -> Option { self.map.get(k) } } 

Qual è il modo corretto di scrivere la funzione di ricerca senza copiare la stringa nella tabella hash?

Quando RefCell prestito da un RefCell , il riferimento che ottieni ha una durata inferiore rispetto a quella di RefCell . Questo perché la durata del riferimento è limitata dalla guardia restituita da un borrow() . Quella guardia assicura che nessun altro possa prendere un riferimento mutabile al valore finché la guardia non viene lasciata cadere.

Tuttavia, stai cercando di restituire un valore senza tenere in vita una guardia. Se Frame aveva un metodo che prendeva un argomento &self , ma provava a mutare la mappa (cosa ansible con RefCell – se non hai bisogno di farlo, allora RefCell il RefCell e scrivi e RefCell su &mut self sui metodi che mutano la mappa), potresti distruggere accidentalmente una String cui qualcun altro ha un riferimento. Questo è esattamente il tipo di errori che il controllore del prestito è stato progettato per segnalare!

Se i valori della mappa sono effettivamente immutabili (ovvero il tuo tipo non consentirà la modifica dei valori della mappa), potresti anche racchiuderli in un Rc nella mappa. È quindi ansible restituire un clone di Rc (questo clona solo il puntatore conteggiato di riferimento, non la stringa sottostante), che consente di rilasciare il prestito sulla mappa prima di tornare dalla funzione.

 struct Frame { map: RefCell>> } impl Frame { fn lookup(&self, k: &String) -> Option> { self.map.borrow().get(k).map(|x| x.clone()) } }