Rust 标准库提供了Vec<T>
、HashMap<K, V>
和HashSet<T>
等基本数据结构。这三种数据结构在大多数编程场景中最为常用,其设计符合 Rust 安全、并发的目标。
Vec<T>
Vec是 Rust 中最常用动态数组实现。
rust
fn main() {
// 创建空向量
let mut numbers: Vec<i32> = Vec::new();
// 使用宏创建并初始化向量
let mut names = vec!["Alice", "Bob", "Carol"];
// 向量添加元素
numbers.push(1);
numbers.push(2);
numbers.push(3);
numbers.pop(); // 移除并返回最后一个元素
// 访问向量中的元素
if let Some(first_name) = names.get(0) {
println!("第一个名字是:{}", first_name);
}
// 遍历向量元素
for name in &names {
println!("{}", name);
}
// 修改向量中的元素
if let Some(first_name) = names.get_mut(0) {
*first_name = "Dave";
}
// 使用迭代器处理向量元素
let numbers_squared: Vec<i32> = numbers.iter().map(|&x| x * x).collect();
println!("平方数:{:?}", numbers_squared);
// 用额外元素扩展向量
numbers.extend([4, 5, 6].iter().copied());
// 直接使用索引访问元素
println!("第二个名字:{}", names[1]); // 注意:直接索引可能引发恐慌
}
向量适用于处理相同类型的元素序列,无论是字符串、整数还是自定义类型。
HashMap<K, V>
HashMap<K, V>使用哈希实现键值存储。
rust
use std::collections::HashMap;
fn main() {
// 创建空哈希表
let mut book_reviews: HashMap<String, String> = HashMap::new();
// 向哈希表中添加元素
book_reviews.insert("The Hobbit".to_string(), "优秀的奇幻书籍".to_string());
book_reviews.insert("The Catcher in the Rye".to_string(), "经典小说".to_string());
// 访问哈希表中的元素
if let Some(review) = book_reviews.get("The Hobbit") {
println!("《霍比特人》的评论:{}", review);
}
// 从哈希表中移除元素
book_reviews.remove("The Catcher in the Rye");
// 遍历哈希表
for (book, review) in &book_reviews {
println!("{}: {}", book, review);
}
// 更新哈希表中的元素
book_reviews.entry("The Hobbit".to_string()).or_insert("未找到评论".to_string());
book_reviews.entry("1984".to_string()).or_insert("反乌托邦科幻小说".to_string());
let mut scores = HashMap::new();
// 使用 `insert` 直接插入
scores.insert("Blue", 10);
scores.insert("Blue", 25); // 覆盖之前的值
// 使用 `entry` 更新或插入
scores.entry("Yellow").or_insert(50); // 插入,因为 "Yellow" 不存在
scores.entry("Blue").or_insert(50); // 无操作,因为 "Blue" 已存在
// 结果:{"Blue": 25, "Yellow": 50}
// 检查键是否存在
if book_reviews.contains_key("1984") {
println!("1984 的评论可用。");
}
}
HashSet<T>
HashSet是存储不重复元素的无序集合。它使用哈希表实现,提供查找、插入和删除操作。
rust
use std::collections::HashSet;
fn main() {
// 创建空集合
let mut numbers = HashSet::new();
// 向集合中添加元素
numbers.insert(1);
numbers.insert(2);
numbers.insert(3);
// 从集合中移除元素
numbers.remove(&3);
// 检查元素是否存在于集合中
if numbers.contains(&1) {
println!("1 在集合中");
}
// 遍历集合
for number in &numbers {
println!("{}", number);
}
// 集合操作:并集、交集、差集、对称差集
// 此时,numbers 包含 {1, 2}
let other_numbers = [2, 3, 4].iter().cloned().collect::<HashSet<_>>();
// other_numbers 包含 {2, 3, 4}
let union = numbers.union(&other_numbers).cloned().collect::<HashSet<_>>();
println!("并集:{:?}", union);
// 并集:`{1, 2, 3, 4}`(两个集合中的所有唯一元素)
let intersection = numbers.intersection(&other_numbers).cloned().collect::<HashSet<_>>();
println!("交集:{:?}", intersection);
// 交集:`{2}`(共同元素)
let difference = numbers.difference(&other_numbers).cloned().collect::<HashSet<_>>();
println!("差集:{:?}", difference);
// 差集:`{1}`(在 `numbers` 中但不在 `other_numbers` 中的元素)
let symmetric_difference = numbers.symmetric_difference(&other_numbers).cloned().collect::<HashSet<_>>();
println!("对称差集:{:?}", symmetric_difference);
// 对称差集:`{1, 3, 4}`(每个集合中唯一的元素)
}
双向链表(LinkedList<T>
)
LinkedList<T>
是 Rust 标准库提供的双向链表。与向量(Vec<T>
)相比,链表允许插入和删除元素,尤其是在列表开头或结尾处。然而,它们在随机访问方面表现不佳。
rust
use std::collections::LinkedList;
fn main() {
// 创建新的空链表
let mut list: LinkedList<i32> = LinkedList::new();
// 向列表尾部添加元素
list.push_back(1);
list.push_back(2);
// 向列表头部添加元素
list.push_front(0);
// 从列表头部和尾部弹出元素
assert_eq!(list.pop_front(), Some(0));
assert_eq!(list.pop_back(), Some(2));
// 遍历列表
for elem in list.iter() {
println!("{}", elem);
}
// 修改列表中的元素(需要使用迭代器)
let mut iter_mut = list.iter_mut();
if let Some(first_elem) = iter_mut.next() {
*first_elem = 3;
}
// 打印修改后的列表
println!("修改后的列表:{:?}", list);
}
当需要频繁在列表开头或结尾处添加或删除元素时,LinkedList
是不错的选择,因为这些操作的时间复杂度为 O(1)。
如果应用程序很少需要随机访问,那么链表比向量更合适。
BTreeMap<K, V>
BTreeMap<K, V>
使用 B 树实现键值集合。它保持键的排序顺序。与哈希表(HashMap<K, V>
)相比,BTreeMap
在有序遍历时表现出色。
rust
use std::collections::BTreeMap;
fn main() {
// 创建新的空 BTreeMap
let mut map: BTreeMap<String, i32> = BTreeMap::new();
// 向 BTreeMap 中插入键值对
map.insert("apple".to_string(), 3);
map.insert("banana".to_string(), 2);
map.insert("pear".to_string(), 4);
// 获取对应键的值
if let Some(v) = map.get("apple") {
println!("apple: {}", v);
}
// 移除键值对
map.remove("banana");
// 遍历 BTreeMap
for (key, value) in &map {
println!("{}: {}", key, value);
}
// 范围查询:获取 "apple" 和 "pear"(含)之间所有键值对
let range = map.range("apple".to_string()..="pear".to_string());
for (key, value) in range {
println!("范围查询:{}: {}", key, value);
}
}
当需要自动排序时,BTreeMap
是不错的选择。
如果程序频繁进行有序的查找、插入和删除操作,BTreeMap
可能比 HashMap
更合适,因为它保持键的顺序,便于有序遍历。
B 树集(BTreeSet<T>
)
BTreeSet<T>
基于 B 树实现的集合。它存储唯一元素并保持其排序顺序。与 HashSet<T>
相比,BTreeSet
支持有序操作和范围查询,但某些操作可能较慢。
rust
use std::collections::BTreeSet;
fn main() {
// 创建新的空 BTreeSet
let mut set: BTreeSet<i32> = BTreeSet::new();
// 向集合中添加元素
set.insert(12);
set.insert(5);
set.insert(18);
// 检查元素是否存在
if set.contains(&12) {
println!("集合包含 12");
}
// 移除元素
set.remove(&5);
// 遍历集合(元素将按升序排列)
for num in &set {
println!("{}", num);
}
// 范围查询:获取大于等于 10 且小于 20 的所有元素
for num in set.range(10..20) {
println!("范围查询:{}", num);
}
}
当需要有序集合进行快速查找、范围查询或有序遍历时,BTreeSet
是不错的选择。
BinaryHeap<T>
BinaryHeap<T>
是基于二叉堆实现的优先队列。它允许快速插入元素和移除最大(或最小)元素,具体取决于它是最大堆还是最小堆。默认情况下,Rust 的 BinaryHeap
是最大堆。
rust
use std::collections::BinaryHeap;
fn main() {
// 创建新的空 BinaryHeap
let mut heap = BinaryHeap::new();
// 向堆中添加元素
heap.push(1);
heap.push(5);
heap.push(2);
// 查看堆中的最大元素而不移除它
if let Some(max) = heap.peek() {
println!("最大元素:{}", max);
}
// 移除并返回最大元素
println!("移除的最大元素:{}", heap.pop().unwrap());
// 遍历堆(迭代顺序未排序)
for num in &heap {
println!("{}", num);
}
}
当需要快速访问和移除最大(或最小)元素时,BinaryHeap
理想选择。这在 Dijkstra 最短路径等算法中尤为有用。
BinaryHeap
适用于任务调度、贪心算法或任何需要优先队列的场景。