rust hashmap 全面使用指南

我来详细介绍 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 代码更加高效。

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容