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