簡體   English   中英

如何在 Rust 中創建具有默認值的 HashMap?

[英]How does one create a HashMap with a default value in Rust?

作為 Rust 的新手,我想知道如何使用鍵的默認值創建HashMap 例如,對於HashMap中插入的任何鍵,都具有默認值0

在 Rust 中,我知道這會創建一個空的 HashMap:

let mut mymap: HashMap<char, usize> = HashMap::new();

我希望為一組鍵維護一個計數器,其中一種方法似乎是:

for ch in "AABCCDDD".chars() {
    mymap.insert(ch, 0)
}

有沒有辦法在 Rust 中以更好的方式做到這一點,也許相當於 Ruby 提供的東西:

mymap = Hash.new(0)
mymap["b"] = 1
mymap["a"] # 0

回答你遇到的問題...

我希望為一組鍵維護一個計數器。

然后你想看看如何有效地查找並插入 HashMap? . 提示: *map.entry(key).or_insert(0) += 1


回答你問的問題...

如何在 Rust 中創建具有默認值的 HashMap?

不, HashMap沒有存儲默認值的地方。 這樣做會導致該數據結構的每個用戶都分配空間來存儲它,這將是一種浪費。 您還必須處理沒有適當默認值或無法輕松創建默認值的情況。

相反,您可以使用HashMap::get查找值,並在缺少時使用Option::unwrap_or提供默認值:

use std::collections::HashMap;

fn main() {
    let mut map: HashMap<char, usize> = HashMap::new();
    map.insert('a', 42);

    let a = map.get(&'a').cloned().unwrap_or(0);
    let b = map.get(&'b').cloned().unwrap_or(0);

    println!("{}, {}", a, b); // 42, 0
}

如果unwrap_or不適用於您的情況,有幾個類似的功能可能:

當然,歡迎您將其包裝在函數或數據結構中以提供更好的 API


ArtemGr 提出了一個有趣的觀點

在 C++ 中,有一個映射的概念,即在訪問鍵時插入默認值 不過,這似乎總是有點漏:如果類型沒有默認值怎么辦? Rust 對映射類型的要求較低,並且對鍵的存在(或不存在)更為明確。

Rust 對此增加了額外的皺紋。 實際上插入一個值需要簡單地獲取一個值也可以更改HashMap 這將使對HashMap中值的任何現有引用無效,因為可能需要重新分配。 因此,您將不再能夠同時獲得對兩個值的引用! 那將是非常嚴格的。

使用entry從 HashMap 中獲取一個元素,然后修改它呢?

從文檔:

fn entry(&mut self, key: K) -> Entry<K, V>

獲取地圖中給定鍵的對應條目以進行就地操作。

例子

use std::collections::HashMap;

let mut letters = HashMap::new();

for ch in "a short treatise on fungi".chars() {
    let counter = letters.entry(ch).or_insert(0);
    *counter += 1;
}

assert_eq!(letters[&'s'], 2);
assert_eq!(letters[&'t'], 3);
assert_eq!(letters[&'u'], 1);
assert_eq!(letters.get(&'y'), None);

.or_insert() 和 .or_insert_with()

添加到.entry().or_insert()的現有示例中,我想提一下,如果傳遞給.or_insert()的默認值是動態生成的,最好使用.or_insert_with()

使用.or_insert_with()如下,如果鍵已經存在,則不會生成默認值。 它僅在必要時創建。

        for v in 0..s.len() {
            components.entry(unions.get_root(v))
                      .or_insert_with(|| vec![]) // vec only created if needed.
                      .push(v);
        }

在下面的片段中,每次調用都會生成傳遞給.or_insert()的默認向量。 如果密鑰存在,則會創建一個向量,然后將其丟棄,這可能是一種浪費。

            components.entry(unions.get_root(v))
                      .or_insert(vec![])        // vec always created.
                      .push(v);

因此,對於沒有太多創建開銷的固定值,請使用.or_insert() ,對於具有可觀創建開銷的值,請使用.or_insert_with()

使用初始值啟動映射的一種方法是從元組向量構造映射。 例如,考慮下面的代碼:

let map = vec![("field1".to_string(), value1), ("field2".to_string(), value2)].into_iter().collect::<HashMap<_, _>>();

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM