文章目录
在Rust中Vec、HashMap和HashSet是非常常用的集合类型,它们是通过标准库std::vec和std::collections模块提供的。
Vec: 用于存储动态数组,支持增、删、查、改等操作,适用于元素顺序访问。
HashMap<K, V>: 存储键值对的哈希表,提供高效的查找、插入、删除操作,适用于映射关系。
HashSet: 不允许重复元素的哈希集合,支持高效的插。
这里介绍一下这三个集合类型的用法。
Vec 动态数组
Vec是Rust中用于存储可变大小、同类型元素的集合类型。Vec是一个堆分配的数据结构,允许动态添加或删除元素。
创建动态数组
使用Vec::new()来创建一个空的Vec。
使用vec![]宏来创建并初始化一个Vec。
//创建一个空的Vec
let mut v: Vec<i32> = Vec::new();
//使用宏创建并初始化Vec
let v2 = vec![1, 2, 3, 4]; // 类型推导为 Vec<i32>
增加删除元素
push(): 将元素添加到 Vec 的末尾。
pop(): 从 Vec 中移除并返回最后一个元素。
insert(): 在指定位置插入元素。
remove(): 移除指定位置的元素。
drain(): 删除指定范围的元素。
split_off(): 以指定位置索引为标志,分割数组。
//添加和移除元素
let mut v = Vec::new();
//向Vec添加元素
v.push(1);
v.push(2);
//移除最后一个元素
println!("Last element: {:?}", v.pop());
println!("Vec after pop: {:?}", v);
//在位置1插入元素10
v.insert(1, 10);
println!("Vec after insert: {:?}", v);
//移除索引为0的元素
v.remove(0);
let mut v1 = vec![11, 22, 33, 44, 55];
//删除指定范围的元素,同时获取被删除元素的迭代器
let mut m: Vec<_> = v1.drain(1..=3).collect();
//指定索引处切分成两个 vec, m: [22], v2: [33, 44]
let v2 = m.split_off(1);
访问元素
使用索引或切片来访问Vec中的元素。
使用get()方法来安全地访问元素,避免数组越界。
let v = vec![10, 20, 30, 40];
println!("First element: {}", v[0]); // 使用索引访问
//使用get方法它返回一个 Option
match v.get(1) {
Some(value) => println!("Second element: {}", value),
None => println!("No element at this index"),
}
遍历Vec
可以使用for循环、iter()方法等来遍历Vec。
let v = vec![1, 2, 3, 4];
for val in &v {
println!("{}", val); // 值的借用
}
for val in v.iter() {
println!("{}", val); // 使用 iter()
}
控制容量
调整动态数组的容量大小。
//指定空间
let mut v = Vec::with_capacity(10);
v.extend([1, 2, 3]);
//调整空间
v.reserve(100);
//释放剩余的容量,一般情况下,不会主动去释放容量
v.shrink_to_fit();
修改元素
可以通过索引或iter_mut()来修改元素。
let mut v = vec![1, 2, 3, 4];
//使用索引修改元素
v[2] = 30;
println!("Vec after modification: {:?}", v);
//使用iter_mut()修改元素
for val in &mut v {
*val *= 2; // 通过引用修改值
}
println!("Vec after multiplying by 2: {:?}", v);
元素排序
在rust里实现了两种排序算法,分别为稳定的排序sort和sort_by,以及非稳定排序sort_unstable和sort_unstable_by。
非稳定并不是指排序算法本身不稳定,而是指在排序过程中对相等元素的处理方式。在稳定排序算法里,对相等的元素,不会对其进行重新排序。而在不稳定的算法里则不保证这点。总体而言非稳定排序的算法的速度会优于稳定排序算法,同时稳定排序还会额外分配原数组一半的空间。
//整数元素排序
fn main() {
let mut vec = vec![1, 5, 10, 2, 15];
vec.sort_unstable();
assert_eq!(vec, vec![1, 2, 5, 10, 15]);
}
在浮点数当中存在一个NAN值,这个值无法与其他的浮点数进行对比,因此浮点数类型并没有实现全数值可比较Ord的特性,而是实现了部分可比较的特性PartialOrd。如此,如果我们确定在我们的浮点数数组当中,不包含NAN值,那么我们可以使用partial_cmp来作为大小判断的依据。
fn main() {
let mut vec = vec![1.0, 5.6, 10.3, 2.0, 15f32];
vec.sort_unstable_by(|a, b| a.partial_cmp(b).unwrap());
assert_eq!(vec, vec![1.0, 2.0, 5.6, 10.3, 15f32]);
}
定义自定义排序方法对结构体进行排序
//实现 Ord、Eq、PartialEq、PartialOrd 这些属性 便可以使用默认排序 不需要自定义了
/*
#[derive(Debug, Ord, Eq, PartialEq, PartialOrd)]
struct Person {
name: String,
age: u32,
}*/
#[derive(Debug)]
struct Person {
name: String,
age: u32,
}
impl Person {
fn new(name: String, age: u32) -> Person {
Person { name, age }
}
}
fn main() {
let mut people = vec![
Person::new("Zoe".to_string(), 25),
Person::new("Al".to_string(), 60),
Person::new("John".to_string(), 1),
];
//定义一个按照年龄倒序排序的对比函数
people.sort_unstable_by(|a, b| b.age.cmp(&a.age));
}
HashMap<K, V>哈希表
HashMap是一个存储键值对(key-value)的集合类型,提供了通过键(key)高效查找、插入和删除值(value)的能力。
创建 HashMap
使用HashMap::new()创建一个空的HashMap。
使用hashmap![]宏来创建并初始化一个HashMap。
use std::collections::HashMap;
let mut map = HashMap::new();
map.insert("name", "Alice");
map.insert("age", "30");
// 使用宏创建并初始化 HashMap
// 如果你希望使用hashmap!宏,确保你导入了maplit库,并在代码中使用#[macro_use]来启用宏。
let mut map2 = hashmap! {
"name" => "Bob",
"age" => "25",
};
插入和更新元素
insert(key, value): 将键值对插入到HashMap中,如果键已存在则更新对应的值。
let mut map = HashMap::new();
map.insert("name", "Alice");
map.insert("age", "30");
// 插入一个已存在的键,值会被更新
map.insert("age", "31");
println!("Updated map: {:?}", map);
访问元素
使用get()方法安全地查找键对应的值返回Option。
使用索引语法map[key]会在键不存在时panic。
let map = HashMap::from([("name", "Alice"), ("age", "30")]);
// 使用 get() 方法返回 Option
match map.get("name") {
Some(value) => println!("Name: {}", value),
None => println!("No value found for key 'name'"),
}
// 使用索引访问元素(可能会 panic)
println!("Age: {}", map["age"]);
删除元素
remove(): 根据键删除键值对,返回被删除的值。
let mut map = HashMap::new();
map.insert("name", "Alice");
map.insert("age", "30");
map.remove("age");
println!("After removal: {:?}", map);
遍历HashMap
可以使用for循环来遍历HashMap。
let map = HashMap::from([("name", "Alice"), ("age", "30")]);
for (key, value) in &map {
println!("Key: {}, Value: {}", key, value);
}
使用默认值
可以使用entry()方法与or_insert()方法来为不存在的键插入默认值。
let mut map = HashMap::new();
map.entry("name").or_insert("Alice");
map.entry("age").or_insert("30");
println!("{:?}", map);
HashSet哈希集合
HashSet是一个不允许重复元素的集合类型,基于哈希表实现。它提供了高效的插入、删除和查找操作。
创建 HashSet
使用 HashSet::new() 创建一个空的 HashSet。
使用 hashset![] 宏来创建并初始化一个 HashSet。
use std::collections::HashSet;
let mut set = HashSet::new();
set.insert(1);
set.insert(2);
set.insert(3);
// 使用宏创建并初始化 HashSet
let set2: HashSet<_> = [1, 2, 3].iter().cloned().collect();
插入和删除元素
insert(): 向集合中插入元素,如果该元素已存在,则不会插入。
remove(): 从集合中移除元素。
let mut set = HashSet::new();
set.insert(1);
set.insert(2);
set.insert(2); // 重复的元素不会被插入
set.remove(&1);
println!("Set after removal: {:?}", set);
查找元素
使用contains()方法检查集合中是否包含某个元素。
let set: HashSet<_> = [1, 2, 3].iter().cloned().collect();
if set.contains(&2) {
println!("Set contains 2");
} else {
println!("Set does not contain 2");
}
遍历HashSet
可以使用for循环来遍历HashSet。
let set: HashSet<_> = [1, 2, 3].iter().cloned().collect();
for val in &set {
println!("{}", val);
}
使用集合的并集、交集等操作
HashSet提供了集合运算的方法如并集、交集、差集等。
use std::collections::HashSet;
let set1: HashSet<_> = [1, 2, 3].iter().cloned().collect();
let set2: HashSet<_> = [3, 4, 5].iter().cloned().collect();
// 并集
let union: HashSet<_> = set1.union(&set2).cloned().collect();
println!("Union: {:?}", union);
// 交集
let intersection: HashSet<_> = set1.intersection(&set2).cloned().collect();
println!("Intersection: {:?}", intersection);