基础概念
HashMap 是 Rust 标准库中的一个集合类型,它是一个基于哈希表实现的键值对映射容器。HashMap 允许你根据键(key)快速查找和修改对应的值(value)。它在 Rust 中广泛用于存储具有唯一键的关联数据。
- 键值对存储:
HashMap存储的是一组键值对,每个键(key)是唯一的,值(value)可以是任何类型。 - 无序性:
HashMap是无序的,即它的元素是根据哈希函数来存储的,因此无法保证插入的顺序与遍历的顺序相同。 - 哈希函数:
HashMap使用哈希函数将键映射到特定的位置,这使得查找操作非常高效。默认情况下,Rust 使用 SipHash 哈希算法。
创建 HashMap
你可以通过以下方式创建 HashMap:
use std::collections::HashMap;
fn main() {
// 创建一个空的 HashMap
let mut map = HashMap::new();
// 使用 `insert` 添加元素
map.insert("apple", 3);
map.insert("banana", 5);
// from 函数
let mut map = HashMap::from([("a", 1), ("b", 2)]);
println!("{:?}", map); // 输出: {"a": 1, "b": 2}
}
常用操作与方法
添加键值对
insert(key, value):插入一个新的键值对。如果键已存在,返回旧的值(如果有的话)。let mut map = HashMap::new(); map.insert("key1", 100); map.insert("key2", 200); println!("{:?}", map); // 输出: {"key1": 100, "key2": 200}
获取值
-
get(&key):根据键获取值,返回Option<&V>类型。如果键不存在,返回None。let mut map = HashMap::new(); map.insert("apple", 3); map.insert("banana", 5); if let Some(&value) = map.get("apple") { println!("The value for 'apple' is {}", value); // 输出: 3 } -
contains_key(&key):检查某个键是否存在于HashMap中。let mut map = HashMap::new(); map.insert("apple", 3); map.insert("banana", 5); if map.contains_key("banana") { println!("Found 'banana' in the map"); }
删除键值对
remove(&key):根据键删除对应的键值对,返回被删除的值(如果有的话)。let mut map = HashMap::new(); map.insert("apple", 3); map.insert("banana", 5); map.remove("apple"); println!("{:?}", map); // 输出: {"banana": 5}
清空所有元素
clear():删除所有的键值对,但不改变HashMap的容量。let mut map = HashMap::new(); map.insert("apple", 3); map.insert("banana", 5); map.clear(); println!("{:?}", map); // 输出: {}
遍历 HashMap
你可以使用 for 循环来遍历 HashMap 中的所有键值对。注意,HashMap 的元素是以 (&K, &V) 形式提供的引用。
let mut map = HashMap::new();
map.insert("apple", 3);
map.insert("banana", 5);
for (key, value) in &map {
println!("{}: {}", key, value);
}
// 输出:
// apple: 3
// banana: 5
获取所有键和值
keys():获取所有的键。values():获取所有的值。
let mut map = HashMap::new();
map.insert("apple", 3);
map.insert("banana", 5);
// 获取所有键
for key in map.keys() {
println!("{}", key); // 输出: apple banana
}
// 获取所有值
for value in map.values() {
println!("{}", value); // 输出: 3 5
}
获取键值对的可变引用
entry(key):提供一种 API,允许你检查和操作HashMap中某个键的值。如果键不存在,可以插入一个默认值。
let mut map = HashMap::new();
map.insert("apple", 3);
map.insert("banana", 5);
map.entry("apple").or_insert(10); // 如果 "apple" 已经存在,就不插入新值
map.entry("pear").or_insert(4); // 如果 "pear" 不存在,就插入 "pear": 4
println!("{:?}", map); // 输出: {"apple": 3, "banana": 5, "pear": 4}
按键访问和修改
get_mut(&key):获取某个键对应的可变引用,允许修改该键的值。
let mut map = HashMap::new();
map.insert("apple", 3);
if let Some(value) = map.get_mut("apple") {
*value = 10;
}
println!("{:?}", map); // 输出: {"apple": 10}
内存管理与性能
容量与负载因子
- 容量(Capacity):
HashMap会根据实际需要自动调整容量,以避免频繁地重新分配内存。通常,HashMap会在元素增加时动态扩容,以提高性能。 - 负载因子(Load Factor):
HashMap的负载因子通常设定为0.75,即当元素数量超过容量的 75% 时,HashMap会进行扩容。
扩容策略
当 HashMap 的元素超过当前容量时,它会重新分配内存,通常会将容量扩展到原来的两倍。这是为了保持哈希表查找操作的平均时间复杂度为 O(1)。
use std::collections::HashMap;
fn main() {
let mut map = HashMap::new();
map.insert("apple", 3);
map.insert("banana", 5);
map.reserve(10); // 为了避免后续频繁扩容,预先分配更多的内存
println!("Capacity after reserve: {}", map.capacity());
}
重要特点
键值对的不可重复性
HashMap要求键必须是唯一的。如果你插入一个已有键的键值对,新的值会覆盖旧的值。
let mut map = HashMap::new();
map.insert("apple", 3);
map.insert("apple", 10); // 覆盖 "apple" 对应的值
println!("{:?}", map); // 输出: {"apple": 10}
HashMap 的顺序不保证
HashMap 的元素存储是无序的,因此不能依赖插入顺序。
let mut map = HashMap::new();
map.insert("apple", 3);
map.insert("banana", 5);
map.insert("cherry", 7);
for (key, value) in &map {
println!("{}: {}", key, value);
}
// 输出顺序可能为:
// cherry: 7
// banana: 5
// apple: 3
应用场景
存储和查询关联数据:当你需要根据键快速查找对应的值时,HashMap 是一个非常理想的选择。