2015-06-30 15 views
7

Angenommen, ich habe eine HashMap und ich möchte eine veränderbare Referenz auf einen Eintrag erhalten, oder wenn dieser Eintrag nicht existiert Ich möchte eine veränderbare Referenz auf ein neues Objekt, wie kann ich es tun? Ich habe versucht, unwrap_or(), so etwas wie dies mit:Default veränderbarer Wert von 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. 
} 

Aber das funktioniert nicht, weil die Lebensdauer der Vec nicht lang genug ist. Gibt es eine Möglichkeit, Rust mitzuteilen, dass ich die zurückgegebene Vec die gleiche Lebensdauer wie foo() haben möchte? Ich meine, es diese offensichtliche Lösung ist, aber ich fühle mich wie sollte es einen besseren Weg geben:

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

Sie möchten dies tun, ohne 'Dummy' an irgendeiner Stelle in die Karte einzufügen? Ich frage mich nur. – bluss

+0

Genau, obwohl es nur eine Vorliebe in meinem speziellen Anwendungsfall ist. Obwohl ich mir Situationen vorstellen kann, in denen man nicht "Dummy" einfügen möchte. – Timmmm

Antwort

10

Wie Shepmaster erwähnt, hier ist ein Beispiel für die Eintragung der Verwendung Muster. Es scheint zuerst recht ausführlich zu sein, aber dies vermeidet die Zuweisung eines Arrays, das Sie möglicherweise nicht verwenden, wenn Sie es nicht benötigen. Ich bin sicher, Sie könnten eine generische Funktion, um dies machen auf dem Geschwätz zu reduzieren :)

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"); 
} 

Dies gilt auch für or_insert verkürzt werden kann, wie ich gerade entdeckt!

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

Verwenden von ['or_insert'] (http://doc.rust-lang.org/std/collections/hash_map/enum.Entry.html#method.or_insert) ist die kürzere Version ([Beispiel] (http: // ist .gd/GQYapJ)). – Shepmaster

6

Wenn Sie Ihren dummy in die Karte hinzufügen möchten, dann ist dies ein Duplikat How to properly use HashMap::entry? oder Want to add to HashMap using pattern match, get borrow mutable more than once at a time (oder irgendeine Frage über die entry API).

Wenn Sie es nicht hinzufügen möchten, dann ist Ihr Code in Ordnung, Sie müssen nur den Compiler-Fehlermeldungen folgen, um es zu beheben. Sie versuchen, ein Schlüsselwort als Bezeichner (ref) zu verwenden, und Sie benötigen eine wandelbar Referenz-dummy (& mut dummy) zu erhalten:

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() {} 
Verwandte Themen