2015-02-14 15 views
52

mi piacerebbe fare quanto segue:Come cercare e inserire in una HashMap in modo efficiente?

  • Lookup un Vec per una determinata chiave, e conservarla per un uso successivo.
  • Se non esiste, creare uno Vec vuoto per la chiave, ma mantenerlo nella variabile.

Come eseguire questa operazione in modo efficiente? Naturalmente ho pensato che avrei potuto usare match:

use std::collections::HashMap; 

// This code doesn't compile. 
let mut map = HashMap::new(); 
let key = "foo"; 
let values: &Vec<isize> = match map.get(key) { 
    Some(v) => v, 
    None => { 
     let default: Vec<isize> = Vec::new(); 
     map.insert(key, default); 
     &default 
    } 
}; 

Quando ho provato, mi ha dato errori come:

error[E0502]: cannot borrow `map` as mutable because it is also borrowed as immutable 
    --> src/main.rs:11:13 
    | 
7 |  let values: &Vec<isize> = match map.get(key) { 
    |          --- immutable borrow occurs here 
... 
11 |    map.insert(key, default); 
    |    ^^^ mutable borrow occurs here 
... 
15 | } 
    | - immutable borrow ends here 

ho finito con il fare qualcosa di simile, ma non mi piace il fatto che esegue la ricerca per due volte (map.contains_key e map.get):

// This code does compile. 
let mut map = HashMap::new(); 
let key = "foo"; 
if !map.contains_key(key) { 
    let default: Vec<isize> = Vec::new(); 
    map.insert(key, default); 
} 
let values: &Vec<isize> = match map.get(key) { 
    Some(v) => v, 
    None => { 
     panic!("impossiburu!"); 
    } 
}; 

c'è un modo sicuro per fare questo con un solo match?

risposta

64

Lo entry API è progettato per questo. In forma di manuale, potrebbe assomigliare

use std::collections::hash_map::Entry; 

let values: &Vec<isize> = match map.entry(key) { 
    Entry::Occupied(o) => o.into_mut(), 
    Entry::Vacant(v) => v.insert(default) 
}; 

Oppure si può utilizzare il modulo più breve:

map.entry(key).or_insert_with(|| default) 

Se default è OK/a buon mercato per calcolare anche quando non viene inserito, può anche solo be:

map.entry(key).or_insert(default) 
+0

Grazie per un anser veloce! Ora ho imparato che dovrei esaminare un po 'in profondità i documenti. –

+5

il problema con entry() è che devi sempre clonare la chiave, c'è un modo per evitarlo? – Pascalius

Problemi correlati