Hash Map
约 961 字大约 3 分钟
2025-08-03
Hash Map 通过 HashMap<K, V> 存储一个键值类型 K 对应一个值类型 V 的映射。Hash Map 可以用于需要任何类型作为键来寻找数据的情况,而不是向 Vector 通过索引
创建 Hash Map
与创建 Vector 类似,创建 Hash Map 也使用 new 方法,具体为: HashMap::new()
use std::collections::HashMap;
fn main() {
let mut hash_map = HashMap::new();
}注
- Hash Map 较另外两种方式相比使用较少,所以并没有被 prelude 自动引用。因此在使用时需要导入标准库中集合部分的 HashMap,且没有内建的宏
- 与 Vector 类似,Hash Map 的 键值与键值、值与值之间类型必须都是相同类型
Hash Map 的使用
向 Hash Map 中增加元素使用 insert 方法,调用该方法将会返回一个 Option<V>
增加元素
use std::collections::HashMap;
fn main() {
let mut hash_map = HashMap::new();
hash_map.insert(String::from("Blue"), 10);
hash_map.insert(String::from("Yellow"), 50);
println!("{:?}", hash_map);
}重复键的覆盖行为
使用相同的键多次 insert 会覆盖旧值
重要
- 在被覆盖时返回
Some(旧值),首次插入则返回None
重复插入并判断是否覆盖
use std::collections::HashMap;
fn main() {
let mut hash_map = HashMap::new();
hash_map.insert(String::from("Blue"), 10);
hash_map.insert(String::from("Yellow"), 50);
// 如果返回 Some(old),说明此键已存在且被覆盖;None 表示第一次插入
let prev = hash_map.insert(String::from("Yellow"), 60);
if let Some(old) = prev {
println!("替换发生,旧值: {old}");
} else {
println!("没有覆盖,这是第一次插入该键");
}
println!("{:?}", hash_map);
}entry
如果只想 在键不存在时插入或需要基于旧值做累加 可以使用 entry 方法。该方法返回一个 Entry 枚举,用来区分当前键是否存在
缺省插入与累加
use std::collections::HashMap;
fn main() {
let mut scores = HashMap::new();
// Blue 不存在时才插入 10
scores.entry(String::from("Blue")).or_insert(10);
scores.insert(String::from("Yellow"), 50);
// 基于旧值累加:或插入 0,然后解引用累加
*scores.entry(String::from("Blue")).or_insert(0) += 5;
println!("{scores:?}");
}注
or_insert只在当前键不存在时插入默认值;若键已存在,直接返回旧值的可变引用,不会调用插入逻辑- 返回值始终是该键对应值的可变引用,便于就地修改
- 若默认值构造开销大,可用
or_insert_with(|| expensive_default())延迟创建
获取值
与 Vector 类似,Hash Map 获取值的方式也是通过 get 方法,其同样也会返回一个 Option<&V> 类型
get 方法获取值
use std::collections::HashMap;
fn main() {
let mut scores = HashMap::new();
scores.insert(String::from("Blue"), 10);
scores.insert(String::from("Yellow"), 50);
let team_name = String::from("Blue");
// get 首先会返回一个 Option<&i32>
// 然后 copied 方法会把 Option<&i32> 变为 Option<i32>
// 以便 get 获取为空时设置默认值
// 如果不 copied 则可以直接 .unwrap_or(&0);
let score = scores.get(&team_name).copied().unwrap_or(0);
}for 循环获取
use std::collections::HashMap;
fn main() {
let mut scores = HashMap::new();
scores.insert(String::from("Blue"), 10);
scores.insert(String::from("Yellow"), 50);
for (key, value) in &scores {
println!("{key}: {value}");
}
}Hash Map 与 所有权
对于像 i32 这种实现了 Copy Trait 的类型,其值可以拷贝进 Hash Map。而对于像 String 这样拥有所有权的值,其值将被移动而 Hash Map 会成为这些值的所有者,因此如果后续需要继续使用,则需调用 clone 或 &
Hash Map 与 所有权
use std::collections::HashMap;
fn main() {
let field_name = String::from("Favorite color");
let field_value = String::from("Blue");
let mut hash_map = HashMap::new();
hash_map.insert(field_name, field_value);
// 后续 field_name 与 field_value 将无法继续使用
}