Struct std::collections::hash_map::HashMap 1.0.0[−][src]
pub struct HashMap<K, V, S = RandomState> { /* fields omitted */ }
Expand description
通过二次探测和 SIMD 查找实现的 哈希表。
默认情况下,HashMap
使用选择为提供对 HashDoS 攻击的抵抗力的哈希算法。
该算法是随机播种的,并且做出了合理的努力以从主机提供的高质量,安全的随机性源生成此 seed,而不会阻塞程序。
因此,seed 的随机性取决于创建 seed 时系统随机数发生器的输出质量。
特别地,当系统的熵池异常低时 (例如在系统引导期间) 生成的种子可能具有较低的质量。
当前的默认哈希算法是 SipHash 1-3,尽管它可能会在 future 的任何位置进行更改。 虽然它的性能对于中等大小的键非常有竞争力,但其他哈希算法对于小键 (如整数) 和大键 (如长字符串) 的性能将优于它,尽管这些算法通常不能防止诸如 HashDoS 之类的攻击。
可以使用 default
,with_hasher
和 with_capacity_and_hasher
方法在每个 HashMap
的基础上替换哈希算法。
hashing algorithms available on crates.io 有很多替代方案。
尽管通常可以通过使用 #[derive(PartialEq, Eq, Hash)]
来实现,但要求键实现 Eq
和 Hash
traits。
如果您自己实现这些,那么拥有以下属性非常重要:
k1 == k2 -> hash(k1) == hash(k2)
换句话说,如果两个键相等,则它们的哈希值必须相等。
以这样一种方式修改键是一个逻辑错误,即键的哈希 (由 Hash
特征确定) 或其相等性 (由 Eq
特征确定) 在更改时发生变化在 map 上。
通常只有通过 Cell
,RefCell
,二进制状态,I/O 或不安全代码才能实现此操作。
未指定由此类逻辑错误导致的行为,但不会导致未定义的行为。
这可能包括 panics,不正确的结果,异常终止,内存泄漏和未终止。
哈希表实现是 Google SwissTable 的 Rust 端口。 可以在 这里 找到 SwissTable 的原始 C++ 版本,而该 CppCon 讨论 概述了该算法的工作原理。
Examples
use std::collections::HashMap;
// 通过类型推断,我们可以省略显式类型签名 (在本示例中为 `HashMap<String, String>`)。
let mut book_reviews = HashMap::new();
// 复习一些书。
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(),
);
// 检查一个特定的。
// 当集合存储拥有的值 (String) 时,仍可以使用引用 (&str) 来查询它们。
if !book_reviews.contains_key("Les Misérables") {
println!("We've got {} reviews, but Les Misérables ain't one.",
book_reviews.len());
}
// 糟糕,此评论有很多拼写错误,让我们删除它。
book_reviews.remove("The Adventures of Sherlock Holmes");
// 查找与某些键关联的值。
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)
}
}
// 查找某个键的值 (如果找不到该键,就会出现 panic)。
println!("Review for Jane: {}", book_reviews["Pride and Prejudice"]);
// 遍历所有内容。
for (book, review) in &book_reviews {
println!("{}: \"{}\"", book, review);
}
Run可以从数组初始化具有已知项列表的 HashMap
:
use std::collections::HashMap;
let solar_distance = HashMap::from([
("Mercury", 0.4),
("Venus", 0.7),
("Earth", 1.0),
("Mars", 1.5),
]);
RunHashMap
实现了一个 Entry API
,它允许获取、设置、更新和删除键及其值的复杂方法:
use std::collections::HashMap;
// 通过类型推断,我们可以省略显式类型签名 (在本示例中为 `HashMap<&str, u8>`)。
let mut player_stats = HashMap::new();
fn random_stat_buff() -> u8 {
// 实际上可以在这里返回一些随机值 - 现在让我们返回一些固定值
42
}
// 仅在键不存在时才插入
player_stats.entry("health").or_insert(100);
// 仅当一个键不存在时,才使用提供新值的函数插入该键
player_stats.entry("defence").or_insert_with(random_stat_buff);
// 更新键,以防止键可能未被设置
let stat = player_stats.entry("attack").or_insert(100);
*stat += random_stat_buff();
Run将 HashMap
与自定义键类型一起使用的最简单方法是派生 Eq
和 Hash
。
我们还必须导出 PartialEq
。
use std::collections::HashMap;
#[derive(Hash, Eq, PartialEq, Debug)]
struct Viking {
name: String,
country: String,
}
impl Viking {
/// 创建一个新的 Viking。
fn new(name: &str, country: &str) -> Viking {
Viking { name: name.to_string(), country: country.to_string() }
}
}
// 使用 HashMap 存储 Viking 的健康点。
let vikings = HashMap::from([
(Viking::new("Einar", "Norway"), 25),
(Viking::new("Olaf", "Denmark"), 24),
(Viking::new("Harald", "Iceland"), 12),
]);
// 使用派生的实现来打印 Viking 的状态。
for (viking, health) in &vikings {
println!("{:?} has {} hp", viking, health);
}
RunImplementations
创建一个空的 HashMap
,它将使用给定的哈希生成器来哈希键。
创建的 map 具有默认的初始容量。
警告: hash_builder
通常是随机生成的,旨在使 HashMaps 能够抵抗导致许多冲突和非常差的性能的攻击。
使用此函数手动设置它可能会导致 DoS 攻击 vector。
传递的 hash_builder
应该为 HashMap 实现 BuildHasher
trait 才有用,有关详细信息,请参见其文档。
Examples
use std::collections::HashMap;
use std::collections::hash_map::RandomState;
let s = RandomState::new();
let mut map = HashMap::with_hasher(s);
map.insert(1, 2);
Run创建一个具有指定容量的空 HashMap
,使用 hash_builder
对键进行哈希运算。
哈希 map 将能够至少保留 capacity
个元素而无需重新分配。如果 capacity
为 0,则不会分配哈希 map。
警告: hash_builder
通常是随机生成的,旨在使 HashMaps 能够抵抗导致许多冲突和非常差的性能的攻击。
使用此函数手动设置它可能会导致 DoS 攻击 vector。
传递的 hash_builder
应该为 HashMap 实现 BuildHasher
trait 才有用,有关详细信息,请参见其文档。
Examples
use std::collections::HashMap;
use std::collections::hash_map::RandomState;
let s = RandomState::new();
let mut map = HashMap::with_capacity_and_hasher(10, s);
map.insert(1, 2);
Run创建一个消费迭代器,以任意顺序访问所有键。
调用后不能使用 map。
迭代器元素类型为 K
。
Examples
use std::collections::HashMap;
let map = HashMap::from([
("a", 1),
("b", 2),
("c", 3),
]);
let mut vec: Vec<&str> = map.into_keys().collect();
// `IntoKeys` 迭代器以任意顺序生成键,因此必须对键进行排序以针对排序数组测试它们。
vec.sort_unstable();
assert_eq!(vec, ["a", "b", "c"]);
Run1.54.0[src]pub fn into_values(self) -> IntoValues<K, V>ⓘNotable traits for IntoValues<K, V>impl<K, V> Iterator for IntoValues<K, V> type Item = V;
pub fn into_values(self) -> IntoValues<K, V>ⓘNotable traits for IntoValues<K, V>impl<K, V> Iterator for IntoValues<K, V> type Item = V;
impl<K, V> Iterator for IntoValues<K, V> type Item = V;
创建一个消费迭代器,以任意顺序访问所有值。
调用后不能使用 map。
迭代器元素类型为 V
。
Examples
use std::collections::HashMap;
let map = HashMap::from([
("a", 1),
("b", 2),
("c", 3),
]);
let mut vec: Vec<i32> = map.into_values().collect();
// `IntoValues` 迭代器以任意顺序生成值,因此必须对这些值进行排序以针对已排序数组对其进行测试。
vec.sort_unstable();
assert_eq!(vec, [1, 2, 3]);
Runpub fn drain_filter<F>(&mut self, pred: F) -> DrainFilter<'_, K, V, F>ⓘNotable traits for DrainFilter<'_, K, V, F>impl<K, V, F> Iterator for DrainFilter<'_, K, V, F> where
F: FnMut(&K, &mut V) -> bool, type Item = (K, V);
where
F: FnMut(&K, &mut V) -> bool,
pub fn drain_filter<F>(&mut self, pred: F) -> DrainFilter<'_, K, V, F>ⓘNotable traits for DrainFilter<'_, K, V, F>impl<K, V, F> Iterator for DrainFilter<'_, K, V, F> where
F: FnMut(&K, &mut V) -> bool, type Item = (K, V);
where
F: FnMut(&K, &mut V) -> bool,
impl<K, V, F> Iterator for DrainFilter<'_, K, V, F> where
F: FnMut(&K, &mut V) -> bool, type Item = (K, V);
创建一个迭代器,该迭代器使用闭包确定是否应删除元素。
如果闭包返回 true,则将元素从 map 中移除并产生。 如果闭包返回 false 或 panics,则该元素保留在 map 中,并且不会产生。
请注意,无论选择保留还是删除 drain_filter
,您都可以对过滤器闭包中的每个值进行可变的。
如果迭代器仅被部分消耗或根本没有被消耗,则其余所有元素仍将受到闭包的处理,如果返回 true,则将其删除并丢弃。
如果在闭包中出现 panic,或者在丢弃元素时发生 panic,或者 DrainFilter
值泄漏,将有多少个元素受到该闭包的影响,这是不确定的。
Examples
将 map 分为偶数和奇数键,重新使用原始的 map:
#![feature(hash_drain_filter)]
use std::collections::HashMap;
let mut map: HashMap<i32, i32> = (0..8).map(|x| (x, x)).collect();
let drained: HashMap<i32, i32> = map.drain_filter(|k, _v| k % 2 == 0).collect();
let mut evens = drained.keys().copied().collect::<Vec<_>>();
let mut odds = map.keys().copied().collect::<Vec<_>>();
evens.sort();
odds.sort();
assert_eq!(evens, vec![0, 2, 4, 6]);
assert_eq!(odds, vec![1, 3, 5, 7]);
Run降低 map 的容量。 它将降低不低于提供的限制,同时保持内部规则,并可能根据调整大小策略留下一些空间。
如果当前容量小于下限,则为无操作。
Examples
use std::collections::HashMap;
let mut map: HashMap<i32, i32> = HashMap::with_capacity(100);
map.insert(1, 2);
map.insert(3, 4);
assert!(map.capacity() >= 100);
map.shrink_to(10);
assert!(map.capacity() >= 10);
map.shrink_to(0);
assert!(map.capacity() >= 2);
Run在 map 中获取给定键的对应项,以进行就地操作。
Examples
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);
Run将键值对插入 map。
如果 map 不存在此键,则返回 None
。
如果 map 确实存在此键,则更新值,并返回旧值。
但是,键不会更新。对于不能相同的 ==
类型来说,这一点很重要。
有关更多信息,请参见 模块级文档。
Examples
use std::collections::HashMap;
let mut map = HashMap::new();
assert_eq!(map.insert(37, "a"), None);
assert_eq!(map.is_empty(), false);
map.insert(37, "b");
assert_eq!(map.insert(37, "c"), Some("b"));
assert_eq!(map[&37], "c");
Run尝试将键值对插入到 map 中,并向条目中的值返回变量引用。
如果 map 已经存在此键,则不进行任何更新,并返回包含占用项和值的错误。
Examples
基本用法:
#![feature(map_try_insert)]
use std::collections::HashMap;
let mut map = HashMap::new();
assert_eq!(map.try_insert(37, "a").unwrap(), &"a");
let err = map.try_insert(37, "b").unwrap_err();
assert_eq!(err.entry.key(), &37);
assert_eq!(err.entry.get(), &"a");
assert_eq!(err.value, "b");
Run为 HashMap 创建原始条目构建器。
原始条目为搜索和操作 map 提供了最低级别的控制。必须使用哈希将其手动初始化,然后进行手动搜索。 此后,插入空条目仍然需要提供一个拥有的键。
原始条目对于以下特殊情况很有用:
- 哈希记忆
- 推迟创建拥有的键,直到知道它是必需的为止
- 使用不适用于借用 trait 的搜索键
- 在不使用 newtype 包装器的情况下使用自定义比较逻辑
因为原始条目提供了更多的灵活控制,所以将 HashMap 置于不一致状态要容易得多,这虽然具有内存安全性,但会导致 map 产生看似随机的结果。
如果可能,应首选更高级别且更简单的 API,例如 entry
。
特别是,用于初始化原始条目的哈希必须仍然与最终存储在条目中的键的哈希保持一致。 这是因为 HashMap 的实现在调整大小时可能需要重新计算哈希,此时只有键可用。
原始条目为变量提供了可变的访问权限。 这不能用于修改键的比较或散列方式,因为映射不会重新评估键应该去的位置,这意味着如果它们的位置不反映它们的状态,它们可能会丢失。
例如,如果您更改一个键以使 map 现在包含比较相等的键,则搜索可能会开始不规律地进行,两个键彼此相互掩盖。 实现可以自由地假设不会发生这种情况 (在内存安全性的范围内)。
为 HashMap 创建一个原始的不可变条目构建器。
原始条目为搜索和操作 map 提供了最低级别的控制。 必须使用哈希将其手动初始化,然后进行手动搜索。
这对于
- 哈希记忆
- 使用不适用于借用 trait 的搜索键
- 在不使用 newtype 包装器的情况下使用自定义比较逻辑
除非您处于这种情况下,否则应首选更高级别且更简单的 API,例如 get
。
不可变的原始条目用途非常有限; 您可能需要 raw_entry_mut
。
Trait Implementations
用一个元素扩展一个集合。