关于rust:rust学习在哈希map中存储具有关联值的键

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

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理