ZetCode

Rust HashMap

最后修改于 2025 年 2 月 19 日

在本文中,我们将展示如何在 Rust 中使用 HashMap。

HashMap 是键值对的集合,其中每个键都是唯一的。HashMap 通过键高效地存储和检索数据非常有用。

要在 Rust 中使用 HashMap,我们需要从 std::collections 模块导入 HashMap 类型。

Rust 创建 HashMap

在第一个示例中,我们在 Rust 中创建并初始化 HashMap。

main.rs
use std::collections::HashMap;

fn main() {

    let mut scores = HashMap::new();

    scores.insert(String::from("Blue"), 10);
    scores.insert(String::from("Yellow"), 50);

    println!("{:?}", scores);

    let teams = vec![String::from("Blue"), String::from("Yellow")];
    let initial_scores = vec![10, 50];

    let scores2: HashMap<_, _> = teams.into_iter().zip(initial_scores.into_iter()).collect();
    println!("{:?}", scores2);
}

在示例中,我们创建了两个 HashMap。

let mut scores = HashMap::new();

我们使用 HashMap::new() 创建一个空的 HashMap。mut 关键字使 HashMap 可变,允许我们稍后添加键值对。

scores.insert(String::from("Blue"), 10);
scores.insert(String::from("Yellow"), 50);

我们使用 insert 方法将键值对插入到 HashMap 中。

let scores2: HashMap<_, _> = teams.into_iter().zip(initial_scores.into_iter()).collect();

我们使用 zip 方法和 collect 从两个向量创建 HashMap。

λ cargo run -q
{"Blue": 10, "Yellow": 50}
{"Blue": 10, "Yellow": 50}

Rust 访问 HashMap 元素

我们可以使用 get 方法访问 HashMap 中的元素。

main.rs
use std::collections::HashMap;

fn main() {
    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);

    match score {
        Some(s) => println!("Score for {}: {}", team_name, s),
        None => println!("Team {} not found", team_name),
    }
}

在示例中,我们访问与键 "Blue" 关联的值。

let score = scores.get(&team_name);

get 方法返回一个 Option<&V>,如果键存在则为 Some,如果键不存在则为 None

λ cargo run -q
Score for Blue: 10

Rust 更新 HashMap

我们可以使用 insert 方法更新 HashMap 中的值。

main.rs
use std::collections::HashMap;

fn main() {
    let mut scores = HashMap::new();

    scores.insert(String::from("Blue"), 10);
    scores.insert(String::from("Yellow"), 50);

    println!("Before update: {:?}", scores);

    scores.insert(String::from("Blue"), 25);

    println!("After update: {:?}", scores);
}

在示例中,我们更新了与键 "Blue" 关联的值。

λ cargo run -q
Before update: {"Blue": 10, "Yellow": 50}
After update: {"Blue": 25, "Yellow": 50}

使用 for 循环

我们可以使用 for 循环遍历 HashMap 中的键值对。

main.rs
use std::collections::HashMap;

fn main() {
    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);
    }
}

在示例中,我们遍历 HashMap 并打印每个键值对。

λ cargo run -q
Blue: 10
Yellow: 50

使用 while 循环

我们可以使用 while 循环遍历 HashMap 中的键值对。

main.rs
use std::collections::HashMap;`

fn main() {
    let mut fruits: HashMap<i32, String> = HashMap::new();
    fruits.insert(1, String::from("Apple"));
    fruits.insert(2, String::from("Banana"));
    fruits.insert(3, String::from("Cherry"));

    let mut iterator = fruits.iter(); // Obtain an iterator

    while let Some((key, value)) = iterator.next() {
        println!("Key: {}, Value: {}", key, value);
    }
}

我们遍历 HashMap 并打印每个键值对。

let mut iterator = fruits.iter(); // Obtain an iterator

我们使用 fruits.iter 显式创建一个迭代器。

while let Some((key, value)) = iterator.next() {
    println!("Key: {}, Value: {}", key, value);
}

只要迭代器产生一个 Some 值(即,还有更多元素),while let 循环就会继续。

iterator.next 将下一个键值对检索为 Option<(key, value)>。如果键值对存在,循环会解构它,打印键和值。

λ cargo run -q
Key: 2, Value: Banana
Key: 1, Value: Apple
Key: 3, Value: Cherry

Rust HashMap 删除

我们可以使用 remove 方法从 HashMap 中删除键值对。此方法接受要从 HashMap 中删除的键的引用。

main.rs
use std::collections::HashMap;

fn main() {
    let mut scores = HashMap::new();

    scores.insert(String::from("Red"), 20);
    scores.insert(String::from("Green"), 40);
    scores.insert(String::from("Blue"), 60);

    println!("Before remove: {:?}", scores);

    scores.remove(&String::from("Green"));

    println!("After remove: {:?}", scores);
}

在此示例中,我们创建了一个名为 scores 的可变 HashMap 来存储团队名称及其分数。

scores.insert(String::from("Red"), 20); 
scores.insert(String::from("Green"), 40); 
scores.insert(String::from("Blue"), 60); 

我们将三个键值对插入到 HashMap 中,分别代表三个团队:“Red” 分数 20,“Green” 分数 40,“Blue” 分数 60。

scores.remove(&String::from("Green"));

我们使用 remove 方法删除与键 "Green" 关联的键值对。remove 方法接受键的引用,这就是为什么我们使用 &String::from("Green")

λ cargo run -q
Before remove: {"Red": 20, "Green": 40, "Blue": 60}
After remove: {"Red": 20, "Blue": 60}

Rust HashMap 键

我们可以使用 keys 方法迭代存储在 HashMap 中的键。此方法返回一个产生 HashMap 中每个键引用的迭代器。

main.rs
use std::collections::HashMap;

fn main() {
    let mut scores = HashMap::new();

    scores.insert(String::from("Red"), 20);
    scores.insert(String::from("Green"), 40);
    scores.insert(String::from("Blue"), 60);

    println!("HashMap: {:?}", scores);

    println!("Keys:");
    for team in scores.keys() {
        println!("{}", team);
    }
}

在此示例中,我们创建了一个名为 scoresHashMap 来存储团队名称及其分数。

scores.insert(String::from("Red"), 20);
scores.insert(String::from("Green"), 40);
scores.insert(String::from("Blue"), 60);

我们将三个键值对插入到 HashMap 中,分别代表三个团队:“Red” 分数 20,“Green” 分数 40,“Blue” 分数 60。

for team in scores.keys() {
    println!("{}", team);
}

我们使用 keys 方法获取 HashMap 中键的迭代器。for 循环遍历每个键(团队名称)并将其打印到控制台。

λ cargo run -q
HashMap: {"Red": 20, "Green": 40, "Blue": 60}
Keys:
Red
Green
Blue

Rust HashMap 值

我们可以使用 values 方法迭代存储在 HashMap 中的值。此方法返回一个产生 HashMap 中每个值引用的迭代器。

main.rs
use std::collections::HashMap;

fn main() {
    let mut scores = HashMap::new();

    scores.insert(String::from("Red"), 20);
    scores.insert(String::from("Green"), 40);
    scores.insert(String::from("Blue"), 60);

    println!("HashMap: {:?}", scores);

    println!("Values:");
    for score in scores.values() {
        println!("{}", score);
    }
}

在此示例中,我们创建了一个名为 scoresHashMap 来存储团队名称及其分数。

scores.insert(String::from("Red"), 20);
scores.insert(String::from("Green"), 40);
scores.insert(String::from("Blue"), 60);

我们将三个键值对插入到 HashMap 中,分别代表三个团队:“Red” 分数 20,“Green” 分数 40,“Blue” 分数 60。

for score in scores.values() {
    println!("{}", score);
}

我们使用 values 方法获取 HashMap 中值的迭代器。for 循环遍历每个值(分数)并将其打印到控制台。

λ cargo run -q
HashMap: {"Red": 20, "Green": 40, "Blue": 60}
Values:
20
40
60

Rust HashMap entry

entry 允许我们检查键是否存在,并在键不存在时插入一个值。

main.rs
use std::collections::HashMap;

fn main() {
    let mut scores = HashMap::new();

    scores.insert(String::from("Blue"), 10);
    scores.insert(String::from("Yellow"), 50);

    scores.entry(String::from("Blue")).or_insert(25);
    scores.entry(String::from("Red")).or_insert(100);

    println!("{:?}", scores);
}

在示例中,我们使用 entry 方法仅在键不存在时插入值。

λ cargo run -q
{"Blue": 10, "Yellow": 50, "Red": 100}

Rust HashMap 计数元素

我们可以使用 len 方法计算 HashMap 中的键值对数量。

main.rs
use std::collections::HashMap;

fn main() {
    let mut scores = HashMap::new();

    scores.insert(String::from("Blue"), 10);
    scores.insert(String::from("Yellow"), 50);

    println!("Number of elements: {}", scores.len());
}

在示例中,我们计算了 HashMap 中键值对的数量。

λ cargo run -q
Number of elements: 2

Rust HashMap 检查键是否存在

我们可以使用 contains_key 方法检查 HashMap 中是否存在某个键。

main.rs
use std::collections::HashMap;

fn main() {
    let mut scores = HashMap::new();

    scores.insert(String::from("Blue"), 10);
    scores.insert(String::from("Yellow"), 50);

    let team_name = String::from("Blue");

    if scores.contains_key(&team_name) {
        println!("{} exists in the HashMap", team_name);
    } else {
        println!("{} does not exist in the HashMap", team_name);
    }
}

在示例中,我们检查 HashMap 中是否存在键 "Blue"。

λ cargo run -q
Blue exists in the HashMap

Rust HashMap 合并

我们可以使用 extend 方法合并两个 HashMap。

main.rs
use std::collections::HashMap;

fn main() {
    let mut scores1 = HashMap::new();
    scores1.insert(String::from("Blue"), 10);
    scores1.insert(String::from("Yellow"), 50);

    let mut scores2 = HashMap::new();
    scores2.insert(String::from("Red"), 100);
    scores2.insert(String::from("Green"), 75);

    scores1.extend(scores2);

    println!("{:?}", scores1);
}

在示例中,我们将两个 HashMap 合并为一个。

λ cargo run -q
{"Blue": 10, "Yellow": 50, "Red": 100, "Green": 75}

Rust HashMap 清空

我们可以使用 clear 方法从 HashMap 中清除所有键值对。

main.rs
use std::collections::HashMap;

fn main() {
    let mut scores = HashMap::new();

    scores.insert(String::from("Blue"), 10);
    scores.insert(String::from("Yellow"), 50);

    println!("Before clear: {:?}", scores);

    scores.clear();

    println!("After clear: {:?}", scores);
}

在示例中,我们清除了 HashMap 中的所有键值对。

λ cargo run -q
Before clear: {"Blue": 10, "Yellow": 50}
After clear: {}

Rust HashMap 克隆

我们可以使用 clone 方法克隆一个 HashMap。

main.rs
use std::collections::HashMap;

fn main() {
    let mut scores = HashMap::new();

    scores.insert(String::from("Blue"), 10);
    scores.insert(String::from("Yellow"), 50);

    let scores2 = scores.clone();

    println!("Original: {:?}", scores);
    println!("Clone: {:?}", scores2);
}

在示例中,我们克隆了一个 HashMap。

λ cargo run -q
Original: {"Blue": 10, "Yellow": 50}
Clone: {"Blue": 10, "Yellow": 50}

Rust HashMap 迭代和修改

我们可以迭代 HashMap 并修改其值。

main.rs
use std::collections::HashMap;

fn main() {
    let mut scores = HashMap::new();

    scores.insert(String::from("Blue"), 10);
    scores.insert(String::from("Yellow"), 50);

    for (_, value) in &mut scores {
        *value += 10;
    }

    println!("{:?}", scores);
}

在示例中,我们迭代 HashMap 并将每个值增加 10。

λ cargo run -q
{"Blue": 20, "Yellow": 60}

Rust HashMap 从迭代器创建

我们可以从键值对的迭代器创建 HashMap。

main.rs
use std::collections::HashMap;

fn main() {
    let teams = vec![String::from("Blue"), String::from("Yellow")];
    let scores = vec![10, 50];

    let scores_map: HashMap<_, _> = teams.into_iter().zip(scores.into_iter()).collect();

    println!("{:?}", scores_map);
}

在示例中,我们使用 zip 方法从两个向量创建 HashMap。

λ cargo run -q
{"Blue": 10, "Yellow": 50}

Rust HashMap 过滤

我们可以使用 retain 方法过滤 HashMap。

main.rs
use std::collections::HashMap;

fn main() {
    let mut scores = HashMap::new();

    scores.insert(String::from("Blue"), 10);
    scores.insert(String::from("Yellow"), 50);
    scores.insert(String::from("Red"), 100);

    scores.retain(|_, &mut v| v > 20);

    println!("{:?}", scores);
}

在示例中,我们过滤 HashMap,只保留值大于 20 的键值对。

λ cargo run -q
{"Yellow": 50, "Red": 100}

Rust HashMap 按键排序

我们可以使用 BTreeMap 类型按键对 HashMap 进行排序。

main.rs
use std::collections::BTreeMap;

fn main() {
    let mut scores = BTreeMap::new();

    scores.insert(String::from("Blue"), 10);
    scores.insert(String::from("Yellow"), 50);
    scores.insert(String::from("Red"), 100);

    println!("{:?}", scores);
}

在示例中,我们使用 BTreeMap 按键对 HashMap 进行排序。

λ cargo run -q
{"Blue": 10, "Red": 100, "Yellow": 50}

Rust HashMap 按值排序

我们可以通过将其转换为元组向量来按值对 HashMap 进行排序。

main.rs
use std::collections::HashMap;

fn main() {
    let mut scores = HashMap::new();

    scores.insert(String::from("Blue"), 10);
    scores.insert(String::from("Yellow"), 50);
    scores.insert(String::from("Red"), 100);

    let mut sorted_scores: Vec<_> = scores.into_iter().collect();
    sorted_scores.sort_by(|a, b| a.1.cmp(&b.1));

    println!("{:?}", sorted_scores);
}

在示例中,我们按值对 HashMap 进行排序。

let mut sorted_scores: Vec<_> = scores.into_iter().collect();

这会将 scores HashMap 转换为一个元组向量。每个元组包含一个键及其对应的值。into_iter 方法消耗 HashMap 并生成一个迭代器,collect 将迭代器的项收集到一个向量中。

sorted_scores.sort_by(|a, b| a.1.cmp(&b.1));

这会根据元组中的值对 sorted_scores 向量进行排序。sort_by smethod 接受一个闭包,该闭包使用 cmp 方法比较值(a.1b.1)。

λ cargo run -q
[("Blue", 10), ("Yellow", 50), ("Red", 100)]

Rust HashMap 使用自定义键类型

通过实现 EqHash trait,我们可以使用自定义类型作为 HashMap 的键。

main.rs
use std::collections::HashMap;
use std::hash::{Hash, Hasher};

#[derive(Eq, PartialEq)]
struct CustomKey {
    id: u32,
    name: String,
}

impl Hash for CustomKey {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.id.hash(state);
        self.name.hash(state);
    }
}

fn main() {
    let mut scores = HashMap::new();

    let key1 = CustomKey { id: 1, name: String::from("Blue") };
    let key2 = CustomKey { id: 2, name: String::from("Yellow") };

    scores.insert(key1, 10);
    scores.insert(key2, 50);

    println!("{:?}", scores.get(&CustomKey { id: 1, name: String::from("Blue") }));
}

在示例中,我们使用自定义类型作为 HashMap 的键。

λ cargo run -q
Some(10)

Rust HashMap 使用自定义值类型

我们可以在 HashMap 中使用自定义类型作为值。

main.rs
use std::collections::HashMap;

#[derive(Debug)]
struct CustomValue {
    score: u32,
    description: String,
}

fn main() {
    let mut scores = HashMap::new();

    let value1 = CustomValue { score: 10, description: String::from("Good") };
    let value2 = CustomValue { score: 50, description: String::from("Excellent") };

    scores.insert(String::from("Blue"), value1);
    scores.insert(String::from("Yellow"), value2);

    println!("{:?}", scores.get(&String::from("Blue")));
}

在示例中,我们使用自定义类型作为 HashMap 的值。

λ cargo run -q
Some(CustomValue { score: 10, description: "Good" })

Rust HashMap 默认值

我们可以使用 entry 方法为 HashMap 提供默认值。当您想确保某个键始终具有值时,这特别有用,即使它之前没有被显式插入到 HashMap 中。让我们通过一个示例详细了解其工作原理。

main.rs
use std::collections::HashMap;

fn main() {
    let mut scores = HashMap::new();

    scores.insert(String::from("Blue"), 10);
    scores.insert(String::from("Yellow"), 50);

    // Define a team name that doesn't exist in the HashMap
    let team_name = String::from("Red");
    let score = scores.entry(team_name.clone()).or_insert(0);

    println!("{}: {}", team_name, score);
}

在此示例中,我们首先创建一个名为 scores 的可变 HashMap 来存储团队名称及其分数。接下来,我们定义一个当前不在 HashMap 中的团队名称 "Red"。我们使用 entry 来检查键 "Red" 是否存在于 HashMap 中。如果不存在,我们使用 or_insert 方法插入默认值 0。这确保了 HashMap 对于指定的键始终有一个值。

 
scores.insert(String::from("Blue"), 10); 
scores.insert(String::from("Yellow"), 50); 

将一些键值对插入 HashMap。

最后,我们使用 println! 宏打印团队名称及其分数。由于 "Red" 最初不存在于 HashMap 中,因此插入了默认值 0,我们看到输出。

λ cargo run -q
Red: 0

Rust HashMap 容量

我们可以使用 with_capacity 方法创建具有特定容量的 HashMap。

main.rs
use std::collections::HashMap;

fn main() {
    let mut scores = HashMap::with_capacity(10);

    scores.insert(String::from("Blue"), 10);
    scores.insert(String::from("Yellow"), 50);

    println!("Capacity: {}", scores.capacity());
}

在示例中,我们创建了一个容量为 10 的 HashMap。

λ cargo run -q
Capacity: 10

Rust HashMap 从数组创建

我们可以从元组数组创建 HashMap。

main.rs
use std::collections::HashMap;

fn main() {
    let scores: HashMap<_, _> = [
        (String::from("Blue"), 10),
        (String::from("Yellow"), 50),
    ].iter().cloned().collect();

    println!("{:?}", scores);
}

在示例中,我们从元组数组创建了 HashMap。

λ cargo run -q
{"Blue": 10, "Yellow": 50}

Rust HashMap 从向量创建

我们可以从元组向量创建 HashMap。

main.rs
use std::collections::HashMap;

fn main() {
    let scores: HashMap<_, _> = vec![
        (String::from("Blue"), 10),
        (String::from("Yellow"), 50),
    ].into_iter().collect();

    println!("{:?}", scores);
}

在示例中,我们从元组向量创建了 HashMap。

λ cargo run -q
{"Blue": 10, "Yellow": 50}

Rust HashMap 从迭代器创建

我们可以从键值对的迭代器创建 HashMap。

main.rs
use std::collections::HashMap;

fn main() {
    let teams = vec![String::from("Blue"), String::from("Yellow")];
    let scores = vec![10, 50];

    let scores_map: HashMap<_, _> = teams.into_iter().zip(scores.into_iter()).collect();

    println!("{:?}", scores_map);
}

在示例中,我们从键值对的迭代器创建了 HashMap。

λ cargo run -q
{"Blue": 10, "Yellow": 50}

Rust HashMap 从切片创建

我们可以从元组切片创建 HashMap。

main.rs
use std::collections::HashMap;

fn main() {
    let scores: HashMap<_, _> = [
        (String::from("Blue"), 10),
        (String::from("Yellow"), 50),
    ].iter().cloned().collect();

    println!("{:?}", scores);
}

在示例中,我们从元组切片创建了 HashMap。

λ cargo run -q
{"Blue": 10, "Yellow": 50}

Rust HashMap 从范围创建

我们可以从键值对的范围创建 HashMap。

main.rs
use std::collections::HashMap;

fn main() {
    let scores: HashMap<_, _> = (0..5).map(|i| (i, i * 10)).collect();

    println!("{:?}", scores);
}

在示例中,我们从键值对的范围创建了 HashMap。

λ cargo run -q
{0: 0, 1: 10, 2: 20, 3: 30, 4: 40}

Rust HashMap 从元组迭代器创建

我们可以从元组的迭代器创建 HashMap。

main.rs
use std::collections::HashMap;

fn main() {
    let scores: HashMap<_, _> = [
        (String::from("Blue"), 10),
        (String::from("Yellow"), 50),
    ].iter().cloned().collect();

    println!("{:?}", scores);
}

在示例中,我们从元组的迭代器创建了 HashMap。

λ cargo run -q
{"Blue": 10, "Yellow": 50}

Rust HashMap 从键值对迭代器创建

我们可以从键值对的迭代器创建 HashMap。

main.rs
use std::collections::HashMap;

fn main() {
    let teams = vec![String::from("Blue"), String::from("Yellow")];
    let scores = vec![10, 50];

    let scores_map: HashMap<_, _> = teams.into_iter().zip(scores.into_iter()).collect();

    println!("{:?}", scores_map);
}

在示例中,我们从键值对的迭代器创建了 HashMap。

λ cargo run -q
{"Blue": 10, "Yellow": 50}

在本文中,我们学习了 Rust 中的变量。

作者

我叫 Jan Bodnar,是一位充满热情的程序员,拥有丰富的编程经验。我自 2007 年以来一直在撰写编程文章。迄今为止,我已撰写了 1400 多篇文章和 8 本电子书。我在教授编程方面拥有超过十年的经验。

列出 所有 Rust 教程