當前位置: 首頁>>代碼示例 >>用法及示例精選 >>正文


Rust HashMap用法及代碼示例


本文簡要介紹rust語言中 Struct std::collections::HashMap 的用法。

用法

pub struct HashMap<K, V, S = RandomState> { /* fields omitted */ }

通過二次探測和 SIMD 查找實現的hash map

默認情況下,HashMap 使用選定的哈希算法來抵禦 HashDoS 攻擊。該算法是隨機播種的,並且會盡合理的最大努力從主機提供的高質量、安全的隨機源生成此種子,而不會阻塞程序。因此,種子的隨機性取決於係統隨機數生成器在創建種子時的輸出質量。特別是,當係統的熵池異常低時(例如在係統引導期間)生成的種子的質量可能較低。

目前默認的哈希算法是 SipHash 1-3,盡管將來可能會隨時更改。雖然它的性能對於中等大小的 key 非常有競爭力,但對於整數等小 key 以及長字符串等大 key ,其他哈希算法的性能將優於它,盡管這些算法通常無法防禦 HashDoS 等攻擊。

可以使用 default with_hasher with_capacity_and_hasher 方法在每個 HashMap 的基礎上替換哈希算法。有很多替代方案 hashing algorithms available on crates.io

要求鍵實現 Eq Hash 特征,盡管這通常可以通過使用 #[derive(PartialEq, Eq, Hash)] 來實現。如果您自己實現這些,重要的是要滿足以下屬性:

k1 == k2 -> hash(k1) == hash(k2)

換句話說,如果兩個鍵相等,則它們的哈希值必須相等。

以這樣一種方式修改鍵是一個邏輯錯誤,即鍵的哈希(由 Hash 特征確定)或其相等性(由 Eq 特征確定)在映射中發生更改。這通常隻能通過 Cell RefCell 、全局狀態、I/O 或不安全代碼實現。未指定由此類邏輯錯誤導致的行為,但不會導致未定義的行為。這可能包括Panics、不正確的結果、中止、內存泄漏和不終止。

哈希表實現是 Google SwissTable 的 Rust 端口。 SwissTable 的原始 C++ 版本可以在 這裏 中找到,並且 CppCon talk 概述了該算法的工作原理。

例子

use std::collections::HashMap;

// Type inference lets us omit an explicit type signature (which
// would be `HashMap<String, String>` in this example).
let mut book_reviews = HashMap::new();

// Review some books.
book_reviews.insert(
    "Adventures of Huckleberry Finn".to_string(),
    "My favorite book.".to_string(),
);
book_reviews.insert(
    "Grimms' Fairy Tales".to_string(),
    "Masterpiece.".to_string(),
);
book_reviews.insert(
    "Pride and Prejudice".to_string(),
    "Very enjoyable.".to_string(),
);
book_reviews.insert(
    "The Adventures of Sherlock Holmes".to_string(),
    "Eye lyked it alot.".to_string(),
);

// Check for a specific one.
// When collections store owned values (String), they can still be
// queried using references (&str).
if !book_reviews.contains_key("Les Misérables") {
    println!("We've got {} reviews, but Les Misérables ain't one.",
             book_reviews.len());
}

// oops, this review has a lot of spelling mistakes, let's delete it.
book_reviews.remove("The Adventures of Sherlock Holmes");

// Look up the values associated with some keys.
let to_find = ["Pride and Prejudice", "Alice's Adventure in Wonderland"];
for &book in &to_find {
    match book_reviews.get(book) {
        Some(review) => println!("{}: {}", book, review),
        None => println!("{} is unreviewed.", book)
    }
}

// Look up the value for a key (will panic if the key is not found).
println!("Review for Jane: {}", book_reviews["Pride and Prejudice"]);

// Iterate over everything.
for (book, review) in &book_reviews {
    println!("{}: \"{}\"", book, review);
}

可以從數組初始化具有已知項目列表的HashMap

use std::collections::HashMap;

let solar_distance = HashMap::from([
    ("Mercury", 0.4),
    ("Venus", 0.7),
    ("Earth", 1.0),
    ("Mars", 1.5),
]);

HashMap 實現了 Entry API ,它允許使用複雜的方法來獲取、設置、更新和刪除鍵及其值:

use std::collections::HashMap;

// type inference lets us omit an explicit type signature (which
// would be `HashMap<&str, u8>` in this example).
let mut player_stats = HashMap::new();

fn random_stat_buff() -> u8 {
    // could actually return some random value here - let's just return
    // some fixed value for now
    42
}

// insert a key only if it doesn't already exist
player_stats.entry("health").or_insert(100);

// insert a key using a function that provides a new value only if it
// doesn't already exist
player_stats.entry("defence").or_insert_with(random_stat_buff);

// update a key, guarding against the key possibly not being set
let stat = player_stats.entry("attack").or_insert(100);
*stat += random_stat_buff();

HashMap 與自定義鍵類型一起使用的最簡單方法是派生 Eq Hash 。我們還必須派生 PartialEq

use std::collections::HashMap;

#[derive(Hash, Eq, PartialEq, Debug)]
struct Viking {
    name: String,
    country: String,
}

impl Viking {
    /// Creates a new Viking.
    fn new(name: &str, country: &str) -> Viking {
        Viking { name: name.to_string(), country: country.to_string() }
    }
}

// Use a HashMap to store the vikings' health points.
let vikings = HashMap::from([
    (Viking::new("Einar", "Norway"), 25),
    (Viking::new("Olaf", "Denmark"), 24),
    (Viking::new("Harald", "Iceland"), 12),
]);

// Use derived implementation to print the status of the vikings.
for (viking, health) in &vikings {
    println!("{:?} has {} hp", viking, health);
}

相關用法


注:本文由純淨天空篩選整理自rust-lang.org大神的英文原創作品 Struct std::collections::HashMap。非經特殊聲明,原始代碼版權歸原作者所有,本譯文未經允許或授權,請勿轉載或複製。