2015-06-30 18 views
7

Supponiamo di avere un HashMap e voglio ottenere un riferimento mutabile a una voce, o se tale voce non esiste Voglio un riferimento mutabile a un nuovo oggetto, come posso farlo? Ho provato con unwrap_or(), qualcosa di simile:Valore mutabile predefinito da HashMap

fn foo() { 
    let mut map: HashMap<&str, Vec<&str>> = HashMap::new(); 

    let mut ref = map.get_mut("whatever").unwrap_or(&mut Vec::<&str>::new()); 

    // Modify ref. 
} 

Ma questo non funziona perché la durata del Vec non è abbastanza lungo. C'è un modo per dire a Rust che voglio il reso Vec per avere la stessa durata di foo()? Voglio dire, c'è questa soluzione ovvia, ma mi sento come se ci dovrebbe essere un modo migliore:

fn foo() { 
    let mut map: HashMap<&str, Vec<&str>> = HashMap::new(); 

    let mut dummy: Vec<&str> = Vec::new(); 
    let mut ref = map.get_mut("whatever").unwrap_or(&dummy); 

    // Modify ref. 
} 
+5

Si desidera eseguire questa operazione senza inserire 'dummy' nella mappa in qualsiasi punto? Mi stavo solo chiedendo. – bluss

+0

Esattamente, anche se è solo una preferenza nel mio particolare caso d'uso. Anche se posso immaginare situazioni in cui non vorresti inserire 'dummy'. – Timmmm

risposta

10

Come menzionato da Shepmaster, ecco un esempio di utilizzo di voce modello. All'inizio sembra prolisso, ma questo evita di allocare un array che potresti non usare a meno che non ne abbia bisogno. Sono sicuro che si potrebbe fare una funzione generica intorno a questo per ridurre le chiacchiere :)

use std::collections::HashMap; 
use std::collections::hash_map::Entry::{Occupied, Vacant}; 

fn foo() { 
    let mut map = HashMap::<&str, Vec<&str>>::new(); 
    let mut result = match map.entry("whatever") { 
     Vacant(entry) => entry.insert(Vec::new()), 
     Occupied(entry) => entry.into_mut(), 
    }; 

    // Do the work 
    result.push("One thing"); 
    result.push("Then another"); 
} 

Questo può anche essere ridotto a or_insert come ho appena scoperto!

use std::collections::HashMap; 

fn foo() { 
    let mut map = HashMap::<&str, Vec<&str>>::new(); 
    let mut result = map.entry("whatever").or_insert(Vec::new()); 

    // Do the work 
    result.push("One thing"); 
    result.push("Then another"); 
} 
+3

L'utilizzo di ['or_insert'] (http://doc.rust-lang.org/std/collections/hash_map/enum.Entry.html#method.or_insert) è la versione più corta ([Esempio] (http: // is .GD/GQYapJ)). – Shepmaster

6

Se vuoi aggiungere la dummy nella mappa, allora questo è un duplicato di How to properly use HashMap::entry? o Want to add to HashMap using pattern match, get borrow mutable more than once at a time (o qualunque domanda circa l'API entry).

Se non si desidera aggiungerlo, il codice va bene, è sufficiente seguire i messaggi di errore del compilatore per risolverlo. Si sta tentando di utilizzare una parola chiave come un identificatore (ref), ed è necessario per ottenere un di riferimento mutabile-dummy (& mut dummy):

use std::collections::HashMap; 

fn foo() { 
    let mut map: HashMap<&str, Vec<&str>> = HashMap::new(); 

    let mut dummy: Vec<&str> = Vec::new(); 
    let f = map.get_mut("whatever").unwrap_or(&mut dummy); 
} 

fn main() {}