HashMap
- 键值对的形式存储数据,一个键(Key)对应一个值(Value)
- Hash 函数:决定如何在内存中存放 K 和 V
适用场景:通过 K (任何类型) 来寻找数据,而不是通过索引
创建 HashMap
创建空 HashMap:new() 函数
- 添加数据:insert() 方法 ```rust use std::collections::HashMap;
fn main() { // 显示指明类型 或 添加数据
let mut scores: HashMap
```rust
use std::collections::HashMap;
fn main() {
let mut scores = HashMap::new();
scores.insert(String::from("Blue"), 10);
}
HashMap 相关说明
- HashMap 使用的较少,不在 Prelude 中 (预导入模块)
- 标准库对其支持较少,没有内置的宏来创建 HashMap
- 数据存储在 heap 上
同构的。一个 HashMap 中:
在元素类型为 Tuple 的 Vector 上使用 collect 方法,可以组件一个 HashMap
- 要求 Tuple 有两个值L一个作为 K,一个作为 V
- collect 方法可以把数据整合成很多种集合类型,包括 HashMap
- 返回值需要显式指明类型 ```rust use std::collections::HashMap;
fn main() { let teams = vec![String::from(“Blue”), String::from(“Yellow”)]; // String 类型作为球队名称 let initial_scores = vec![10, 50]; // i32 类型作为球队分数
let scores: HashMap<_, _> = teams.iter().zip(initial_scores.iter()).collect();
println!("{:?}", scores);
}
> iter() 方法返回遍历器,使用 zip() 方法创建元组的数组,再使用 collect() 创建 HashMap
> collect() 可以返回很多种不同的集合数据结构,所以需要显式的指明。
> K 和 V 使用两个下划线,因为 Rust 会根据 Vetror 中的数据类型,能推导出 HashMap 的 K 和 V 类型
<a name="SlR77"></a>
### HashMap 和所有权
- 对于实现了 Copy trait 的类型(例如:i32),值会被复制到 HashMap 中。
- 对于拥有所有权的值(例如 String),值会被移动,所有权会转移给 HashMap。
```rust
use std::collections::HashMap;
fn main() {
let field_name = String::from("Favorite color");
let field_value = String::from("Blue");
let mut map = HashMap::new();
map.insert(field_name, field_value);
println!("{:?}", map);
println!("{}: {}", field_name, field_value); // error: borrow of moved value
}
- 如果将值的引用插入到 HashMap,值本身就不会移动 ```rust use std::collections::HashMap;
fn main() { let field_name = String::from(“Favorite color”); let field_value = String::from(“Blue”);
let mut map = HashMap::new();
map.insert(&field_name, &field_value); // 使用值的引用
println!("{:?}", map);
println!("{}: {}", field_name, field_value);
}
- 在 HashMap 有效的期间,被引用的值必须保持有效
<a name="mwn8Q"></a>
### 访问 HashMap 中的值
- get 方法
- 参数:K
- 返回:Option<&V> (返回空的枚举)
```rust
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");
let score = scores.get(&team_name);
match score {
Some(s) => println!("{}", s),
None => println!("team not exist"),
};
}
遍历 HashMap
- for 循环 ```rust use std::collections::HashMap;
fn main() { let mut scores = HashMap::new(); scores.insert(String::from(“Blue”), 10); scores.insert(String::from(“Yellow”), 50); for (k, v) in &scores { // (k, v) 模式匹配相当于元组 println!(“{}: {}”, k, v); } }
<a name="aHyn2"></a>
### 更新 HashMap<K, V>
- HashMap 大小可变
- 每个 K 同时只能对应一个 V
- 更新 HashMap 中的数据:
- K 已经存在,对应一个 V
- 替换现有的 V
- 保留现有的 V,忽略新的 V
- 合并现有的 V 和新的 V
- K 不存在
- 添加一对新的 K,V
<a name="QS5sR"></a>
#### 替换现有的 V
- 如果向 HashMap 插入一对 K,V,然后再插入同样的 K,但是不同的 V,那么原来的 V 会被替换掉。
```rust
use std::collections::HashMap;
fn main() {
let mut scores = HashMap::new();
scores.insert(String::from("Blue"), 10);
scores.insert(String::from("Blue"), 25);
println!("{:?}", scores);
}
只在 K 不对应任何值的情况下,才插入 V
- entry 方法:检查指定的 K 是否对应一个 V
- 参数:K
- 返回 enum Entry:代表值是否存在 ```rust use std::collections::HashMap;
fn main() { let mut scores = HashMap::new(); scores.insert(String::from(“Blue”), 10);
scores.entry(String::from("Yellow")).or_insert(50);
scores.entry(String::from("Blue")).or_insert(50);
println!("{:?}", scores); // {"Blue": 10, "Yellow": 50}
}
- entry 的 or_insert() 方法:
- 返回:
- 如果 K 存在,返回对应的 V 的一个可变引用
- 如果 K 不存在,将方法参数作为 K 的新值插进去,返回到这个值的可变引用
<a name="tEnrc"></a>
#### 基于现有 V 来更新 V
```rust
use std::collections::HashMap;
fn main() {
let text = "hello world wonderful world";
let mut map = HashMap::new();
for word in text.split_whitespace() {
let count = map.entry(word).or_insert(0);
*count += 1;
}
println!("{:#?}", map); // {"hello": 1, "world": 2, "wonderful": 1}
}
Hash 函数
- 默认情况下,HashMap 使用加密功能强大的 Hash 函数,可以抵抗拒绝服务 (DoS) 攻击。
- 不是可用的最快的 Hash 算法
- 但具有更好的安全性
- 可以指定不同的 hasher 来切换到另一个函数
- hasher 是实现 BuildHasher trait 的类型