目录
[1. Rust标准库中的集合概述](#1. Rust标准库中的集合概述)
[2. 常用集合类型](#2. 常用集合类型)
[2.1 向量(Vector)](#2.1 向量(Vector))
[2.2 字符串(String)](#2.2 字符串(String))
[2.3 哈希映射(Hash Map)](#2.3 哈希映射(Hash Map))
[1. 向量的概述](#1. 向量的概述)
[2. 创建向量](#2. 创建向量)
[3. 添加元素](#3. 添加元素)
[4. 访问元素](#4. 访问元素)
[5. 修改元素](#5. 修改元素)
[6. 遍历向量](#6. 遍历向量)
[7. 使用枚举存储多种类型](#7. 使用枚举存储多种类型)
[1. 哈希映射的概述](#1. 哈希映射的概述)
[2. 创建哈希映射](#2. 创建哈希映射)
[3. 插入哈希映射值](#3. 插入哈希映射值)
[4. 访问哈希映射中的值](#4. 访问哈希映射中的值)
[5. 遍历哈希映射](#5. 遍历哈希映射)
[6. 哈希映射的所有权](#6. 哈希映射的所有权)
[7. 更新哈希映射](#7. 更新哈希映射)
[8. 哈希函数](#8. 哈希函数)
思维导图
一、Rust常用集合
1. Rust标准库中的集合概述
Rust的标准库包含了一些非常有用的数据结构,统称为集合(Collections)。与其他数据类型不同,集合可以存储多个值。集合的数据存储在堆上,因此其大小可以在程序运行时动态变化,而不必在编译时确定。
2. 常用集合类型
在Rust中,常用的集合类型主要包括以下三种:
2.1 向量(Vector)
- 定义:向量是一种可以存储可变数量的值的集合。
- 特点:向量的元素在内存中是连续存储的,可以根据需要动态扩展或缩减。
- 使用场景:适合需要频繁插入、删除元素的场合,能够高效地处理动态数据。
2.2 字符串(String)
- 定义:字符串是字符的集合。
- 特点 :Rust中的String类型支持动态大小,可以根据需要进行扩展。
- 使用场景:适用于需要处理文本数据的场合,如用户输入、文件读取等。
2.3 哈希映射(Hash Map)
- 定义:哈希映射是一种将特定键与值关联的数据结构,属于更通用的数据结构"映射"的一种实现。
- 特点:允许通过键快速访问对应的值,适合存储键值对数据。
- 使用场景:常用于需要快速查找、插入和删除的场合,如缓存实现、统计数据等。
二、向量(Vec)
1. 向量的概述
**向量(Vec<T>)**是一种动态数组,可以存储多个相同类型的值。它在内存中是连续存储的,支持高效的随机访问和动态扩展。
2. 创建向量
1)空向量的创建 :使用Vec::new()函数创建一个空向量。例如:
rust
fn main() {
let v: Vec<i32> = Vec::new();[3]
//这里需要类型注释,因为未插入任何值,Rust无法推断元素类型。
}
2) 带初始值的向量 :使用vec!宏创建带初始值的向量。例如:
rust
fn main() {
let v = vec![1, 2, 3];
//Rust可以根据提供的初始值推断类型为Vec<i32>,因此类型注释不再必要。
}
3. 添加元素
添加元素 :使用push方法向向量中添加元素,必须将向量声明为可变(mutable):
rust
fn main() {
let mut v = Vec::new();
v.push(5);
v.push(6);
}
4. 访问元素
访问元素 :可以通过索引或get方法访问向量中的元素。值得注意的是,使用get方法时,如果索引超出范围,返回None,而使用索引直接访问则会导致程序崩溃。例如:
rust
let third: &i32 = &v[2];
let third: Option<&i32> = v.get(2);
5. 修改元素
1)通过索引直接修改: 通过索引可以直接访问并修改向量中的元素。需要注意的是,向量必须是可变的(mut),并且索引必须在有效范围内。例如:
rust
fn main() {
let mut v = vec![1, 2, 3, 4];
// 修改索引为 2 的元素
v[2] = 100;
println!("{:?}", v); // 输出: [1, 2, 100, 4]
}
2)通过get_mut方法修改: get_mut 方法返回一个 Option<&mut T>,允许安全地修改元素。如果索引有效,则返回可变引用;如果索引无效,则返回 None。例如:
rust
fn main() {
let mut v = vec![1, 2, 3, 4];
// 获取索引为 2 的可变引用
if let Some(elem) = v.get_mut(2) {
*elem = 100; // 修改元素
}
println!("{:?}", v); // 输出: [1, 2, 100, 4]
}
6. 遍历向量
1)不可变遍历 :使用for循环遍历向量中的每个元素:
rust
for i in &v {
println!("{i}");
}
2)可变遍历:可以通过可变引用遍历并修改每个元素:
rust
for i in &mut v {
*i += 50;
}
7. 使用枚举存储多种类型
由于向量只能存储相同类型的值,可以使用枚举来存储不同类型的值。例如:
rust
enum SpreadsheetCell {
Int(i32),
Float(f64),
Text(String),
}
let row = vec![
SpreadsheetCell::Int(3),
SpreadsheetCell::Text(String::from("blue")),
SpreadsheetCell::Float(10.12),
];
8.向量的生命周期
向量在超出作用域时会自动释放其内存,所有元素也会随之释放。例如:
rust
{
let v = vec![1, 2, 3, 4];
} // v 超出作用域并被释放
三、字符串(String)
1.字符串的概述
字符串(String
) 是 UTF-8 编码的字符集合,支持动态扩展。Rust 的字符串类型包括 String 和字符串切片 &str。
2.字符串的创建
通过String::new()创建一个新的空字符串,或使用to_string()和String::from()方法从字符串字面量创建字符串。示例代码如下:
rust
fn main() {
let mut s = String::new();
let data = "initial contents";
let s1 = data.to_string();
let s2 = String::from("initial contents");
}
3.字符串的更新
String可以通过push_str方法追加字符串切片,或使用push方法添加单个字符。示例代码如下:
rust
fn main() {
let mut s = String::from("foo");
s.push_str("bar");
s.push('!'); //foobar!
}
4.字符串的连接
可以使用 +操作符或format!宏来连接字符串。使用 +操作符时,左侧字符串会被移动,示例代码如下:
rust
fn main() {
let s1 = String::from("Hello, ");[7][8]
let s2 = String::from("world!");
let s3 = s1 + &s2; // s1被移动,s2仍然有效
}
5.字符串的访问
Rust不支持直接通过索引访问字符串中的字符,需使用chars()方法或bytes()方法进行迭代。例如:
rust
fn main() {
let hello = "Здравствуйте";[7]
for c in hello.chars() {
println!("{c}");
}
}
四、哈希映射(HashMap)
1. 哈希映射的概述
**哈希映射(HashMap<K, V>
)**是一种键值对集合,通过哈希函数将键映射到值。它允许通过键快速查找、插入和删除值。
2. 创建哈希映射
可以使用HashMap::new()方法创建一个空的哈希映射。示例代码:
rust
fn main() {
use std::collections::HashMap;
let mut scores = HashMap::new();
}
3. 插入哈希映射值
可以使用insert方法添加元素。示例代码:
rust
scores.insert(String::from("Blue"), 10);
scores.insert(String::from("Yellow"), 50);
4. 访问哈希映射中的值
可以使用get方法通过键访问对应的值,返回类型为Option<&V>,如果键不存在,则返回None。示例代码:
rust
let score = scores.get(&team_name).copied().unwrap_or(0);
ps: 此程序通过调用 copied 来获取一个 Option<i32> 而不是 Option<&i32> 来处理 Option ,然后如果 scores 没有该键的条目,则调用 unwrap_or 将 score 设置为零。
5. 遍历哈希映射
可以使用for循环遍历哈希映射中的每个键值对。示例代码:
rust
for (key, value) in &scores {
println!("{key}: {value}");
}
6. 哈希映射的所有权
对于实现了Copy特性的类型(如i32),值会被复制到哈希映射中;对于拥有所有权的类型(如String),值会被移动到哈希映射中。示例代码:
rust
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在插入后失效
}
7. 更新哈希映射
1)覆盖值:插入同一键的新值会替换旧值。示例代码:
rust
scores.insert(String::from("Blue"), 10);
scores.insert(String::from("Blue"), 25);
//{"Blue": 25}
2)仅在键不存在时插入 :使用entry
方法检查键是否存在,若不存在则插入新值。示例代码:
rust
scores.entry(String::from("Yellow")).or_insert(50);
ps-1: entry 方法的返回值是一个名为 Entry的枚举,它表示一个可能存在也可能不存在的值。
ps-2: Entry 上的 or_insert 方法被定义为:如果对应的 Entry 键存在,则返回该值的可变引用;如果不存在,则将参数插入作为该键的新值,并返回新值的可变引用。
8. 哈希函数
默认情况下,HashMap使用名为SipHash的哈希函数,具有防止拒绝服务(DoS)攻击的能力。虽然其性能可能不如其他哈希算法,但在安全性和性能之间的权衡是值得的。
tips:
-
向量 :常用操作包括创建(
Vec::new()
、vec![]
)、添加(push
)、访问(索引、get
)、修改(索引、get_mut)和遍历(for
循环)。 -
字符串 :常用操作包括创建(
String::new()
、to_string()
)、更新(push_str
、push
)、连接(+
、format!
)和遍历(chars()
、bytes()
)。 -
哈希映射 :常用操作包括创建(
HashMap::new()
)、插入(insert
)、访问(get
)、遍历(for
循环)和更新(entry
、or_insert
)。