Bir HashMap'ten verimli bir şekilde arama ve ekleme nasıl yapılır?


103

Aşağıdakileri yapmak istiyorum:

  • Bir arama Vecbelirli bir anahtar için, ve daha sonra kullanmak üzere saklayın.
  • Mevcut değilse Vec, anahtar için bir boş oluşturun , ancak yine de değişkende tutun.

Bunu verimli bir şekilde nasıl yapabilirim? Doğal olarak kullanabileceğimi düşündüm 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
    }
};

Denediğimde bana şu hatalar verdi:

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

Sonunda bunun gibi bir şey yaptım, ancak aramayı iki kez yapması hoşuma gitmiyor ( map.contains_keyve 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!");
    }
};

Bunu tek bir cihazla yapmanın güvenli bir yolu var mı match?

Yanıtlar:


121

entryAPI bunun için tasarlanmıştır. Manuel olarak şöyle görünebilir:

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

Veya daha kısa formu kullanabilirsiniz:

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

Eğer defaulttakılı değilse bile hesaplamak için OK / ucuz, aynı zamanda sadece olabilir:

map.entry(key).or_insert(default)

Hızlı cevap için teşekkürler! Artık belgelere biraz daha derinlemesine bakmam gerektiğini öğrendim.
Yusuke Shinyama

23
entry () ile ilgili sorun, her zaman anahtarı klonlamak zorunda olmanız, bundan kaçınmanın bir yolu var mı?
Pascalius

@Pascalius, anahtar türünüzü &T(anahtarlar haritadan daha uzun yaşıyorsa, örneğin statik dizeler) veya Rc<T>yerine T- ama her iki durumda da hoş değil
yapabilirsiniz

@Pascalius: v.key()ifadesinde kullanabilirsin defaultve sonra hashmap'te var olduğu şekliyle anahtara bir referans alır, böylece bu şekilde bir klondan kaçınabilirsin
Chris Beck
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.