当前位置: 首页>>代码示例 >>用法及示例精选 >>正文


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。非经特殊声明,原始代码版权归原作者所有,本译文未经允许或授权,请勿转载或复制。