目录
思维导图
一、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()
函数创建一个空向量。例如:
fn main() {
let v: Vec<i32> = Vec::new();[3]
//这里需要类型注释,因为未插入任何值,Rust无法推断元素类型。
}
2) 带初始值的向量:使用vec!
宏创建带初始值的向量。例如:
fn main() {
let v = vec![1, 2, 3];
//Rust可以根据提供的初始值推断类型为Vec<i32>,因此类型注释不再必要。
}
3. 添加元素
添加元素:使用push
方法向向量中添加元素,必须将向量声明为可变(mutable):
fn main() {
let mut v = Vec::new();
v.push(5);
v.push(6);
}
4. 访问元素
访问元素:可以通过索引或get
方法访问向量中的元素。值得注意的是,使用get
方法时,如果索引超出范围,返回None
,而使用索引直接访问则会导致程序崩溃。例如:
let third: &i32 = &v[2];
let third: Option<&i32> = v.get(2);
5. 修改元素
1)通过索引直接修改:通过索引可以直接访问并修改向量中的元素。需要注意的是,向量必须是可变的(mut
),并且索引必须在有效范围内。例如:
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
。例如:
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
循环遍历向量中的每个元素:
for i in &v {
println!("{i}");
}
2)可变遍历:可以通过可变引用遍历并修改每个元素:
for i in &mut v {
*i += 50;
}
7. 使用枚举存储多种类型
由于向量只能存储相同类型的值,可以使用枚举来存储不同类型的值。例如:
enum SpreadsheetCell {
Int(i32),
Float(f64),
Text(String),
}
let row = vec![
SpreadsheetCell::Int(3),
SpreadsheetCell::Text(String::from("blue")),
SpreadsheetCell::Float(10.12),
];
8.向量的生命周期
向量在超出作用域时会自动释放其内存,所有元素也会随之释放。例如:
{
let v = vec![1, 2, 3, 4];
} // v 超出作用域并被释放
三、字符串(String)
1.字符串的概述
字符串(String
)是 UTF-8 编码的字符集合,支持动态扩展。Rust 的字符串类型包括 String
和字符串切片 &str
。
2.字符串的创建
通过String::new()
创建一个新的空字符串,或使用to_string()
和String::from()
方法从字符串字面量创建字符串。示例代码如下:
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
方法添加单个字符。示例代码如下:
fn main() {
let mut s = String::from("foo");
s.push_str("bar");
s.push('!'); //foobar!
}
4.字符串的连接
可以使用 +
操作符或format!
宏来连接字符串。使用 +操作符时,左侧字符串会被移动,示例代码如下:
fn main() {
let s1 = String::from("Hello, ");[7][8]
let s2 = String::from("world!");
let s3 = s1 + &s2; // s1被移动,s2仍然有效
}
5.字符串的访问
Rust不支持直接通过索引访问字符串中的字符,需使用chars()
方法或bytes()
方法进行迭代。例如:
fn main() {
let hello = "Здравствуйте";[7]
for c in hello.chars() {
println!("{c}");
}
}
四、哈希映射(HashMap)
1. 哈希映射的概述
哈希映射(HashMap<K, V>
)是一种键值对集合,通过哈希函数将键映射到值。它允许通过键快速查找、插入和删除值。
2. 创建哈希映射
可以使用HashMap::new()
方法创建一个空的哈希映射。示例代码:
fn main() {
use std::collections::HashMap;
let mut scores = HashMap::new();
}
3. 插入哈希映射值
可以使用insert
方法添加元素。示例代码:
scores.insert(String::from("Blue"), 10);
scores.insert(String::from("Yellow"), 50);
4. 访问哈希映射中的值
可以使用get
方法通过键访问对应的值,返回类型为Option<&V>
,如果键不存在,则返回None
。示例代码:
let score = scores.get(&team_name).copied().unwrap_or(0);
ps: 此程序通过调用 copied
来获取一个 Option<i32>
而不是 Option<&i32>
来处理 Option
,然后如果 scores
没有该键的条目,则调用 unwrap_or
将 score
设置为零。
5. 遍历哈希映射
可以使用for
循环遍历哈希映射中的每个键值对。示例代码:
for (key, value) in &scores {
println!("{key}: {value}");
}
6. 哈希映射的所有权
对于实现了Copy
特性的类型(如i32
),值会被复制到哈希映射中;对于拥有所有权的类型(如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在插入后失效
}
7. 更新哈希映射
1)覆盖值:插入同一键的新值会替换旧值。示例代码:
scores.insert(String::from("Blue"), 10);
scores.insert(String::from("Blue"), 25);
//{"Blue": 25}
2)仅在键不存在时插入:使用entry
方法检查键是否存在,若不存在则插入新值。示例代码:
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
)。