与向量和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 defaultwarning: 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: 50Blue: 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循环完结时超出范围,因而所有这些更改都是平安的,并且借用规定容许。