HashMap

HashMap

HashMap是由键和值组成的集合。您使用键来查找与键匹配的值。您可以仅使用 HashMap::new() 创建一个新的HashMap,并使用 .insert(key,value)插入项目。

use std::collections::HashMap; // This is so we can just write HashMap instead of std::collections::HashMap every time

struct City {
    name: String,
    population: HashMap<u32, u32>, // This will have the year and the population for the year
}

fn main() {

    let mut tallinn = City {
        name: "Tallinn".to_string(),
        population: HashMap::new(), // So far the HashMap is empty
    };

    tallinn.population.insert(1372, 3_250); // insert three dates
    tallinn.population.insert(1851, 24_000);
    tallinn.population.insert(2020, 437_619);


    for (year, population) in tallinn.population { // The HashMap is HashMap<u32, u32> so it returns a two items each time
        println!("In the year {} the city of {} had a population of {}.", year, tallinn.name, population);
    }
}

In the year 1372 the city of Tallinn had a population of 3250.
In the year 2020 the city of Tallinn had a population of 437619.
In the year 1851 the city of Tallinn had a population of 24000.

HashMap要求一个可哈希(实现Hash trait)的Key类型,和一个编译时知道大小的Value类型。 同时,Rust还要求你的Key类型必须是可比较的,在Rust中,你可以为你的类型轻易的加上编译器属性:

#[derive(PartialEq, Eq, Hash)]

这样,即可将你的类型转换成一个可以作为HashKey的类型。但是,如果你想要自己实现Hash这个trait的话,你需要谨记两点:

    1. 如果Key1==Key2 ,那么一定有Hash(Key1) == Hash(Key2)
    1. 你的Hash函数本身不能改变你的Key值,否则将会引发一个逻辑错误(很难排查,遇到就完的那种)

增删改查

use std::collections::HashMap;

// 声明
let mut come_from = HashMap::new();
// 插入
come_from.insert("WaySLOG", "HeBei");
come_from.insert("Marisa", "U.S.");
come_from.insert("Mike", "HuoGuo");

// 查找key
if !come_from.contains_key("elton") {
    println!("Oh, 我们查到了{}个人,但是可怜的Elton猫还是无家可归", come_from.len());
}

// 根据key删除元素
come_from.remove("Mike");
println!("Mike猫的家乡不是火锅!不是火锅!不是火锅!虽然好吃!");

// 利用get的返回判断元素是否存在
let who = ["MoGu", "Marisa"];
for person in &who {
    match come_from.get(person) {
        Some(location) => println!("{} 来自: {}", person, location),
        None => println!("{} 也无家可归啊.", person),
    }
}

// 遍历输出
println!("那么,所有人呢?");
for (name, location) in &come_from {
    println!("{}来自: {}", name, location);
}

Entry

Rust为我们提供了一个名叫 entryapi,它很有意思,和Python相比,我们不需要在一次迭代的时候二次访问原map,只需要借用entry出来的Entry类型(这个类型持有原有HashMap的引用)即可对原数据进行修改。就语法来说,毫无疑问Rust在这个方面更加直观和具体。

use std::collections::HashMap;

let mut letters = HashMap::new();

for ch in "a short treatise on fungi".chars() {
    let counter = letters.entry(ch).or_insert(0);
    *counter += 1;
}

assert_eq!(letters[&'s'], 2);
assert_eq!(letters[&'t'], 3);
assert_eq!(letters[&'u'], 1);
assert_eq!(letters.get(&'y'), None);

BTreeMap

如果您希望可以对HashMap进行排序,则可以使用BTreeMap。实际上它们彼此非常相似,因此我们可以快速将HashMap更改为BTreeMap进行查看。您可以看到它几乎是相同的代码。

use std::collections::BTreeMap; // Just change HashMap to BTreeMap

struct City {
    name: String,
    population: BTreeMap<u32, u32>, // Just change HashMap to BTreeMap
}

fn main() {

    let mut tallinn = City {
        name: "Tallinn".to_string(),
        population: BTreeMap::new(), // Just change HashMap to BTreeMap
    };

    tallinn.population.insert(1372, 3_250);
    tallinn.population.insert(1851, 24_000);
    tallinn.population.insert(2020, 437_619);

    for (year, population) in tallinn.population {
        println!("In the year {} the city of {} had a population of {}.", year, tallinn.name, population);
    }
}

In the year 1372 the city of Tallinn had a population of 3250.
In the year 1851 the city of Tallinn had a population of 24000.
In the year 2020 the city of Tallinn had a population of 437619.