Rust实战教程:深入理解HashMap集合类型

Rust实战教程:深入理解HashMap集合类型

rust-by-practice Learning Rust By Practice, narrowing the gap between beginner and skilled-dev through challenging examples, exercises and projects. rust-by-practice 项目地址: https://gitcode.com/gh_mirrors/ru/rust-by-practice

HashMap是Rust标准库中提供的键值对集合类型,它通过哈希表实现高效的数据存储和访问。本文将带你全面掌握HashMap的使用方法和内部原理。

HashMap基础概念

HashMap与Vector不同,它通过键(key)而非索引来存储和访问值(value)。Rust的HashMap实现采用了以下关键技术:

  1. 使用二次探测(quadratic probing)解决哈希冲突
  2. 采用SIMD指令加速查找
  3. 默认使用SipHash 1-3哈希算法,提供抗HashDoS攻击能力

SipHash 1-3算法对中等大小的键性能优异,但对于小整数或长字符串等场景,其他哈希算法可能表现更好。

基本操作实战

创建和插入元素

use std::collections::HashMap;

let mut scores = HashMap::new();
scores.insert("Sunface", 98);  // 插入字符串键和整数值
scores.insert("Daniel", 95);

访问和更新元素

// 获取元素,返回Option<&V>
let score = scores.get("Sunface");
assert_eq!(score, Some(&98));

// 直接索引访问(键必须存在)
let daniel_score = scores["Daniel"];

// 检查键是否存在
if scores.contains_key("Daniel") {
    scores.remove("Daniel");  // 删除元素
}

遍历HashMap

for (name, score) in &scores {
    println!("{}: {}", name, score);
}

高级操作技巧

使用entry API

entry API提供了更灵活的元素访问方式:

let mut player_stats = HashMap::new();

// 只在键不存在时插入
player_stats.entry("health").or_insert(100);

// 使用闭包生成默认值
player_stats.entry("health").or_insert_with(|| random_stat_buff());

// 获取可变引用并修改
let health = player_stats.entry("health").or_insert(50);
*health -= 20;

集合转换

可以将其他集合转换为HashMap:

let teams = [("China", 100), ("USA", 10), ("France", 50)];

// 方法1:循环插入
let mut map1 = HashMap::new();
for &(name, score) in &teams {
    map1.insert(name, score);
}

// 方法2:使用collect
let map2: HashMap<_, _> = teams.into_iter().collect();

HashMap键的类型要求

作为HashMap的键,类型必须实现EqHash trait。常见可用作键的类型包括:

  • 布尔值(虽然不太实用)
  • 所有整数类型
  • String和&str(可以混合使用)
  • 实现了相应trait的自定义类型

注意:浮点数(f32/f64)不能作为键,因为浮点精度问题会导致哈希不稳定。

自定义类型作为键

要让自定义类型作为HashMap的键,需要派生EqHash trait:

#[derive(Hash, Eq, PartialEq, Debug)]
struct Viking {
    name: String,
    country: String,
}

let vikings = HashMap::from([
    (Viking::new("Einar", "Norway"), 25),
    (Viking::new("Olaf", "Denmark"), 24)
]);

容量管理

HashMap会根据需要自动增长,也可以手动控制容量:

let mut map = HashMap::with_capacity(100);  // 指定初始容量

map.shrink_to(50);  // 收缩到不小于指定值
map.shrink_to_fit();  // 尽可能收缩

所有权规则

  • 对于实现了Copy trait的类型,值会被复制到HashMap中
  • 对于拥有所有权的类型(如String),值会被移动,HashMap将成为新所有者
let v1 = 10;  // i32实现了Copy
let mut m1 = HashMap::new();
m1.insert(v1, v1);  // v1被复制

let v2 = String::from("hello");
m1.insert(v2, v1);  // v2的所有权被转移
// 这里不能再使用v2

第三方哈希算法

如果需要替代默认的SipHash算法,可以使用第三方哈希库:

use std::hash::BuildHasherDefault;
use twox_hash::XxHash64;

let mut hash: HashMap<_, _, BuildHasherDefault<XxHash64>> = Default::default();
hash.insert(42, "the answer");

第三方哈希算法通常在特定场景下性能更好,但可能不具备抗HashDoS攻击的能力。

通过本文的学习,你应该已经掌握了Rust中HashMap的核心用法和原理。HashMap是Rust中最常用的集合类型之一,合理使用可以大大提高程序的效率和可读性。

rust-by-practice Learning Rust By Practice, narrowing the gap between beginner and skilled-dev through challenging examples, exercises and projects. rust-by-practice 项目地址: https://gitcode.com/gh_mirrors/ru/rust-by-practice

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

张姿桃Erwin

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值