कैसे और कुशलता से एक HashMap में डालने से देखने के लिए?


102

मैं निम्नलिखित करना चाहूंगा:

  • Vecएक निश्चित कुंजी के लिए लुकअप करें , और इसे बाद में उपयोग के लिए स्टोर करें।
  • यदि यह मौजूद नहीं है, Vecतो कुंजी के लिए एक रिक्त बनाएं , लेकिन फिर भी इसे चर में रखें।

यह कुशलता से कैसे करें? स्वाभाविक रूप से मुझे लगा कि मैं इसका उपयोग कर सकता हूं 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
    }
};

जब मैंने इसकी कोशिश की, तो इसने मुझे त्रुटियाँ दीं:

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

मैं इस तरह से कुछ करने के साथ समाप्त हो गया, लेकिन मुझे यह पसंद नहीं है कि यह दो बार ( map.contains_keyऔर 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!");
    }
};

क्या सिर्फ एक के साथ ऐसा करने का एक सुरक्षित तरीका है match?

जवाबों:


119

इसके लिए entryएपीआई डिजाइन किया गया है। मैनुअल रूप में, ऐसा लग सकता है

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

या कोई ब्रीफ़र फॉर्म का उपयोग कर सकता है:

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

यदि defaultडाला नहीं है, तो भी गणना करना ठीक है / सस्ता है, यह भी हो सकता है:

map.entry(key).or_insert(default)

एक तेज एंकर के लिए धन्यवाद! अब मैंने सीखा है कि मुझे दस्तावेजों को थोड़ा गहराई से देखना चाहिए।
युसुके शिनामा

22
प्रविष्टि () के साथ मुद्दा यह है कि, आपको हमेशा कुंजी को क्लोन करना होगा, क्या इससे बचने का कोई तरीका है?
पास्कलियस

@ पास्कलियस आप अपना मुख्य प्रकार बना सकते हैं &T(यदि कुंजी नक्शे को बदल देती है, जैसे स्थैतिक स्ट्रिंग्स) या Rc<T>इसके बजाय T- लेकिन यह किसी भी मामले में सुंदर नहीं है
kbolino

@ पास्कलियस: आप v.key()अभिव्यक्ति के लिए उपयोग कर सकते हैं default, और फिर इसे कुंजी का एक संदर्भ मिलेगा क्योंकि यह हैशमैप में मौजूद है, इसलिए आप इस तरह से क्लोन से बच सकते हैं
क्रिस बेक
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.