我来详细介绍 Rust 中 HashMap 的使用方法。
HashMap 基础用法
1. 引入和创建
use std::collections::HashMap;
fn main() {
// 方法1: 创建空的 HashMap
let mut map: HashMap<String, i32> = HashMap::new();
// 方法2: 使用 with_capacity 预分配容量
let mut map2: HashMap<String, i32> = HashMap::with_capacity(10);
// 方法3: 从迭代器创建
let map3: HashMap<&str, i32> = [("a", 1), ("b", 2), ("c", 3)]
.iter()
.cloned()
.collect();
// 方法4: 使用 HashMap::from (Rust 1.56+)
let map4 = HashMap::from([
("apple", 3),
("banana", 2),
("orange", 5),
]);
}
2. 插入和访问
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");
// 方法1: get() 返回 Option<&V>
match scores.get(&team_name) {
Some(score) => println!("Blue team score: {}", score),
None => println!("Team not found"),
}
// 方法2: 使用 unwrap_or 提供默认值
let score = scores.get(&team_name).unwrap_or(&0);
println!("Score: {}", score);
// 方法3: 使用索引访问 (会 panic 如果键不存在)
// let score = &scores[&team_name]; // 谨慎使用
}
3. 更新值的不同方式
use std::collections::HashMap;
fn main() {
let mut map = HashMap::new();
// 1. 直接覆盖
map.insert("key1", 10);
map.insert("key1", 20); // 覆盖之前的值
// 2. 只在键不存在时插入
map.entry("key2").or_insert(30);
map.entry("key2").or_insert(40); // 不会覆盖,key2 仍然是 30
// 3. 基于现有值更新
let count = map.entry("key3").or_insert(0);
*count += 1; // 增加计数
// 4. 复杂的更新逻辑
map.entry("key4")
.and_modify(|v| *v += 10) // 如果存在,加10
.or_insert(5); // 如果不存在,插入5
println!("{:?}", map);
}
4. 遍历 HashMap
use std::collections::HashMap;
fn main() {
let mut map = HashMap::from([
("apple", 3),
("banana", 2),
("orange", 5),
]);
// 1. 遍历键值对
for (key, value) in &map {
println!("{}: {}", key, value);
}
// 2. 只遍历键
for key in map.keys() {
println!("Key: {}", key);
}
// 3. 只遍历值
for value in map.values() {
println!("Value: {}", value);
}
// 4. 可变遍历值
for value in map.values_mut() {
*value += 1; // 所有值加1
}
// 5. 遍历并获取所有权
for (key, value) in map {
println!("Owned: {} = {}", key, value);
}
// 注意:map 在这里被移动了,后面不能再使用
}
5. 常用方法
use std::collections::HashMap;
fn main() {
let mut map = HashMap::new();
map.insert("a", 1);
map.insert("b", 2);
map.insert("c", 3);
// 检查是否包含键
if map.contains_key("a") {
println!("包含键 'a'");
}
// 获取长度
println!("HashMap 长度: {}", map.len());
// 检查是否为空
if !map.is_empty() {
println!("HashMap 不为空");
}
// 移除键值对
if let Some(value) = map.remove("b") {
println!("移除了 'b': {}", value);
}
// 清空 HashMap
map.clear();
println!("清空后长度: {}", map.len());
// 容量相关
map.reserve(100); // 预留容量
println!("容量: {}", map.capacity());
map.shrink_to_fit(); // 缩减到合适大小
}
6. 处理复杂数据类型
use std::collections::HashMap;
#[derive(Debug)]
struct Student {
name: String,
age: u32,
grade: f64,
}
fn main() {
// HashMap 存储结构体
let mut students: HashMap<u32, Student> = HashMap::new();
students.insert(1, Student {
name: String::from("Alice"),
age: 20,
grade: 85.5,
});
students.insert(2, Student {
name: String::from("Bob"),
age: 19,
grade: 92.0,
});
// 访问结构体字段
if let Some(student) = students.get(&1) {
println!("学生姓名: {}", student.name);
}
// HashMap 存储 Vec
let mut groups: HashMap<String, Vec<String>> = HashMap::new();
groups.entry(String::from("Math")).or_insert(Vec::new())
.push(String::from("Alice"));
groups.entry(String::from("Math")).or_insert(Vec::new())
.push(String::from("Bob"));
println!("{:?}", groups);
}
7. 字符串作为键的注意事项
use std::collections::HashMap;
fn main() {
let mut map = HashMap::new();
// 使用 String 作为键
let key = String::from("hello");
map.insert(key, 42);
// println!("{}", key); // 错误!key 已经被移动
// 解决方案1: 克隆键
let key2 = String::from("world");
map.insert(key2.clone(), 24);
println!("还可以使用 key2: {}", key2);
// 解决方案2: 使用 &str 作为键类型
let mut map2: HashMap<&str, i32> = HashMap::new();
let text = "hello";
map2.insert(text, 42);
println!("还可以使用 text: {}", text);
// 解决方案3: 使用引用插入(需要生命周期管理)
let mut map3 = HashMap::new();
let key3 = String::from("test");
map3.insert(&key3, 42); // 插入引用
println!("还可以使用 key3: {}", key3);
}
8. 实际应用示例
use std::collections::HashMap;
// 计算单词频率
fn word_count(text: &str) -> HashMap<&str, usize> {
let mut counts = HashMap::new();
for word in text.split_whitespace() {
let count = counts.entry(word).or_insert(0);
*count += 1;
}
counts
}
// 分组操作
fn group_by_length(words: Vec<&str>) -> HashMap<usize, Vec<&str>> {
let mut groups = HashMap::new();
for word in words {
groups.entry(word.len())
.or_insert(Vec::new())
.push(word);
}
groups
}
fn main() {
// 单词计数
let text = "hello world hello rust world";
let counts = word_count(text);
for (word, count) in counts {
println!("{}: {}", word, count);
}
// 按长度分组
let words = vec!["cat", "dog", "elephant", "ant", "bear"];
let groups = group_by_length(words);
for (length, words) in groups {
println!("长度 {}: {:?}", length, words);
}
}
9. 性能提示
use std::collections::HashMap;
fn main() {
// 1. 预分配容量以避免重新分配
let mut map = HashMap::with_capacity(1000);
// 2. 使用 entry API 避免重复查找
// 好的做法
*map.entry("key").or_insert(0) += 1;
// 不好的做法(两次查找)
if map.contains_key("key") {
let count = map.get_mut("key").unwrap();
*count += 1;
} else {
map.insert("key", 1);
}
// 3. 批量操作
let data = vec![("a", 1), ("b", 2), ("c", 3)];
let map2: HashMap<_, _> = data.into_iter().collect();
}
这就是 Rust HashMap 的全面使用指南!HashMap 是处理键值对数据的强大工具,掌握这些用法可以让你的 Rust 代码更加高效。