与向量和 Strings 一样,哈希 map 也是也是一种常见的汇合。
HashMap<K,V> 类型存储 K 类型的键到 V 类型的值的映射。它通过散列函数来实现此操作,该函数确定如何将这些键和值搁置到内存中。
创立一个哈希 map:
// 创立一个空哈希 map,并应用 insert 办法进行插值
fn main() {
use std::collections::HashMap;
let mut scores = HashMap::new();
scores.insert(String::from("Blue"), 10);
scores.insert(String::from("Yellow"), 50);
println!("{:?}", scores);
}
D:\learn\cargo_learn>cargo run
Compiling cargo_learn v0.1.0 (D:\learn\cargo_learn)
Finished dev [unoptimized + debuginfo] target(s) in 0.79s
Running `target\debug\cargo_learn.exe`
{"Blue": 10, "Yellow": 50}
请留神,咱们首先须要应用规范库的 collections 局部中的 HashMap。在咱们的三个常见汇合中(vec, STring),该汇合是最不罕用的汇合,因而未蕴含在尾声中主动纳入范畴的性能中。哈企图也没有失去规范库的反对。例如,没有内置的宏能够构建它们。
特地哈希 map 的 key 与 value 都别离是一个 vec(向量),所以务必保障 key 向量的类型统一,value 向量的类型统一;
结构哈企图的另一种办法是在元组的向量上应用迭代器和 collect 办法,其中每个元组都由一个键及其值组成。collect 办法将数据收集到多种收集类型中,包含 HashMap。例如,如果咱们在两个独自的向量中具备名称和初始值,则能够应用 zip 办法创立一个元组向量,其中 ”Blue” 与 10 配对,依此类推。而后,咱们能够应用 collect 办法将元组的矢量转换为哈企图,如下例所示:
fn main() {
use std::collections::HashMap;
let teams = vec![String::from("Blue"), String::from("Yellow")];
let initial_scores = vec![10, 50];
let mut scores: HashMap<_, _> =
teams.into_iter().zip(initial_scores.into_iter()).collect();
println!("{:#?}", scores)
}
D:\learn\cargo_learn>cargo run
Compiling cargo_learn v0.1.0 (D:\learn\cargo_learn)
warning: variable does not need to be mutable
--> src\main.rs:7:9
|
7 | let mut scores: HashMap<_, _> =
| ----^^^^^^
| |
| help: remove this `mut`
|
= note: `#[warn(unused_mut)]` on by default
warning: 1 warning emitted
Finished dev [unoptimized + debuginfo] target(s) in 0.82s
Running `target\debug\cargo_learn.exe`
{
"Yellow": 50,
"Blue": 10,
}
这里须要应用类型正文 HashMap <_,_>,因为它能够收集到许多不同的数据结构中,并且 Rust 除非您指定,否则都不晓得您想要哪个。然而,对于键和值类型的参数,咱们应用下划线,Rust 能够依据向量中数据的类型推断哈希映射蕴含的类型。在上例中,键类型将为 String,而值类型将为 i32。
哈希 map 与所有权
对于实现 Copy 特色的类型,例如 i32,这些值将被复制到哈希 map 中。对于诸如 String 之类的领有的值,这些值将被挪动,并且哈希映射将成为这些值的所有者,如下例所示:
fn main() {
use std::collections::HashMap;
let field_name = String::from("Favorite color");
let field_value = String::from("Blue");
let mut map = HashMap::new();
map.insert(field_name, field_value);
// field_name 与 field_value 在此处及其之后就不可用了,因为他们挪动了,挪动给了 map;}
如果咱们在哈希 map 中插入对值的援用,则这些值将不会移入哈企图中。援用所指向的值必须至多在哈希映射无效期间才无效。
在哈希 map 中拜访值
通过将其 key 提供给 get 办法,咱们能够从哈企图中取得一个值:
fn main() {
use std::collections::HashMap;
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);
println!("{:?}", scores);
println!("{:?}", team_name);
println!("{:?}", score);
}
D:\learn\cargo_learn>cargo run
Compiling cargo_learn v0.1.0 (D:\learn\cargo_learn)
Finished dev [unoptimized + debuginfo] target(s) in 0.74s
Running `target\debug\cargo_learn.exe`
{"Yellow": 50, "Blue": 10}
"Blue"
Some(10)
咱们能够像应用向量一样,应用 for 循环对哈希映射中的每个键 / 值对进行迭代:
fn main() {
use std::collections::HashMap;
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);
}
}
D:\learn\cargo_learn>cargo run
Compiling cargo_learn v0.1.0 (D:\learn\cargo_learn)
Finished dev [unoptimized + debuginfo] target(s) in 0.75s
Running `target\debug\cargo_learn.exe`
Yellow: 50
Blue: 10
更新哈希 map
只管键和值的数量是能够减少的,但每个键一次只能具备一个关联的值。当想更改哈希 map 中的数据时,必须确定在键已调配值的状况下如何解决这种状况。能够用新值替换旧值,而齐全不思考旧值;能够保留旧值,而疏忽新值,仅在键尚无值时才增加新值;或者,能够将旧值和新值联合起来。让咱们看看如何做这些!
替换旧值
通过 insert 办法替换哈希 map 中的值,不论是否曾经存在该属性:
fn main() {
use std::collections::HashMap;
let mut scores = HashMap::new();
scores.insert(String::from("Blue"), 10);
scores.insert(String::from("Blue"), 25);
println!("{:?}", scores);
}
D:\learn\cargo_learn>cargo run
Compiling cargo_learn v0.1.0 (D:\learn\cargo_learn)
Finished dev [unoptimized + debuginfo] target(s) in 0.78s
Running `target\debug\cargo_learn.exe`
{"Blue": 25}
仅当键没有值时才插入值
通过 entry
办法与 or_insert
办法相结合在哈希 map 中插入新纪录如果有老的记录则不作任何操作:
fn main() {
use std::collections::HashMap;
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);
}
D:\learn\cargo_learn>cargo run
Compiling cargo_learn v0.1.0 (D:\learn\cargo_learn)
Finished dev [unoptimized + debuginfo] target(s) in 0.76s
Running `target\debug\cargo_learn.exe`
{"Yellow": 50, "Blue": 10}
entry 办法的返回值是一个称为 Entry 的枚举,它示意一个可能存在或可能不存在的值。
依据旧值更新值
哈希映射的另一个常见用例是查找键的值,而后依据旧值对其进行更新。例如,下例显示了用于计算每个单词在某些文本中呈现的次数的代码。咱们应用以单词为键的哈希 map,并增加值以跟踪咱们看到该单词的次数。如果这是咱们第一次看到一个字,咱们将首先插入值 0:
fn main() {
use std::collections::HashMap;
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);
}
D:\learn\cargo_learn>cargo run
Compiling cargo_learn v0.1.0 (D:\learn\cargo_learn)
Finished dev [unoptimized + debuginfo] target(s) in 0.79s
Running `target\debug\cargo_learn.exe`
{"hello": 1, "wonderful": 1, "world": 2}
此代码将打印 {"hello": 1, "wonderful": 1, "world": 2}
。or_insert 办法实际上返回对此键的值的可变援用(&mut V)。在这里,咱们将该可变援用存储在 count 变量中,因而要调配给该值,咱们必须首先应用星号(*) 勾销援用计数。可变援用在 for 循环完结时超出范围,因而所有这些更改都是平安的,并且借用规定容许。