把 Rust 字符串推 到 Vec String 中很快,因为 Rust 不必复制字符串的字符数据,而 且字符串的所有权始终非常明确。
Rust 没有 null,因此在其他语言会出现 null 的地方 Rust 用 Option 代替
Vec
创建向量最简单的方式是使用 vec! 宏
// 创建空向量
let mut numbers: Vec<i32> = vec![];
// 创建包含给定内容的向量
let words = vec!["step", "on", "no", "pets"];
let mut buffer = vec![0u8; 1024]; // 1024个填充0的字节
Vec 实现了 std::iter::FromIterator。因此可以使 用迭代器的 .collect() 方法基于任何迭代器创建向量
let my_vec = my_set.into_iter().collect::<Vec<String>>();
// 取得一个元素的引用
let first_line = &lines[0];
// 取得一个元素的副本
let fifth_number = numbers[4]; // 要求Copy let second_line = lines[1].clone(); // 要求Clone
// 取得一个切片的引用
let my_ref = &buffer[4..12];
// 取得一个切片的副本
let my_copy = buffer[4..12].to_vec(); // 要求Clone
slice.to_vec() 克隆整个切片,返回一个新向量
let v = [1, 2, 3, 4, 5, 6, 7, 8, 9];
assert_eq!(v.to_vec(),vec![1, 2, 3, 4, 5, 6, 7, 8, 9]);
assert_eq!(v[0..6].to_vec(),
vec![1, 2, 3, 4, 5, 6]);
vec.reserve(n) 确保向量有足够空间容纳另外 个元素。换句话 说,vec.capacity() 至少等于 vec.len() + n。如果容量已经够 了,则什么也不做
vec.retain(test) 移除所有没有通过给定测试的元素
vec.dedup() 清除重复的元素
同时取得多个不可修改引用的数组、切片或向量很容易
let v = vec![0, 1, 2, 3];
let a = &v[i];
let b = &v[j];
let mid = v.len() / 2;
let front_half = &v[..mid];
let back_half = &v[mid..];
但取得多个可修改引用就不容易了:
let mut v = vec![0, 1, 2, 3];
let a = &mut v[i];
let b = &mut v[j]; // error: cannot borrow `v` as mutable
// more than once at a time
Rust 禁止这样操作,因为如果 i == j,那么 a 和 b 就都是对同一 个整数的可修改引用,这违反了 Rust 的安全规则
slice.binary_search(&value)、slice.binary_search_by(&value, cmp) slice.binary_search_by_key(&value, key) 都可以从排 序后的切片中搜索 value。注意 value 传的是引用。
类型 T 支持 == 和 != 操作符(PartialEq 特型)
assert_eq!([1, 2, 3, 4].starts_with(&[1, 2]), true);
assert_eq!([1, 2, 3, 4].starts_with(&[2, 3]), false);
Rust 拒绝在迭代期间修改集合,给出了自己的解释 Rust 在编译时就拒绝了这个程序。在调用 my_vec.iter() 时,循环会借用向量的共享(不可修改)引用。这个引用的生命期与 迭代器一样长,直到 for 循环结束。在存在不可修改引用的情况下, 不能调用 my_vec.remove(index) 修改向量。
可以选择使用
my_vec.retain(|&val| val <= 4);
VecDeque
Vec 只支持在两端高效添加和移除元素。如果程序需要把值保存在队 列中间,Vec 就慢了
Rust 的 std::collections::VecDeque 是一个 (发音 “deck”),即双端队列。它支持前端和后端的高效添加和移除操 作。
- deque.push_front(value)
- deque.push_back(value)
- deque.pop_front()
- deque.pop_back()
- deque.front()
- deque.front_mut()
VecDeque 的实现是环形缓冲区
与向量一样,队列可以按值、按共享引用或按可修改引用迭代。它们 有 3 个迭代器方法:.into_iter()、.iter() 和 .iter_mut()
LinkedList
链表是另一种存储序列值的方式。链表的每个值都存储在独立的堆内 存中
目前来看,LinkedList 比 VecDeque 强大的地方主要体现在组合两个 列表的速度非常快。list.append(&mut list2) 会把 list2 的元素都 转移到 list 中,只需修改几个指针即可,因此时间复杂度是常量
BinaryHeap
BinaryHeap 是一个元素松散组织的集合,而且最大值始终会冒泡到队 列前端
- heap.push(value) 向堆中添加值
- heap.pop() 从堆中移除并返回最大值。返回类型为 Option, 如果堆为空则返回 None
- heap.peek() 返回堆中最大值的引用
use std::collections::BinaryHeap;
let mut heap = BinaryHeap::from(vec![2, 3, 8, 6, 9, 5, 4]);
assert_eq!(heap.peek(), Some(&9));
assert_eq!(heap.pop(), Some(9));
assert_eq!(heap.pop(), Some(8));
assert_eq!(heap.pop(), Some(6));
assert_eq!(heap.pop(), Some(5));
HashMap & BTreeMap
HashMap 把键和值保存在一个散列表中,因此要求键的类型 K 实现标 准的散列和相等性特型 Hash 和 Eq
BTreeMap 按照键的顺序存储条目,总体为树形结构,因此要求键类型 K 实现 Ord
BTreeMap 将条目存储在 中,其中大多数节点只包含键 – 值对。 非叶节点,即图中的根节点,也有保存子节点指针的空间。(20, ‘q’) 和 (30, ‘r’) 之间的指针指向的子节点包含的键介于 20 到 30 之 间。添加条目经常需要将已有节点的条目向右移动以保持顺序,偶尔 也需要分配新节点。
Rust 标准库使用 B 树而不使用平衡二叉树的原因是 B 树在现代硬件 上更快。二叉树每次搜索所需比较的次数可能比 B 树更少,但搜索 B 树的 (locality)更好。换句话说,内存访问集中在一块,而 不是分散到整个堆上。这样 CPU 缓存就很少错失,从而显著提升速 度。
if !student_map.contains_key(name) {
// 没有:创建一个
student_map.insert(name.to_string(), Student::new());
}
let record = student_map.get_mut(name).unwrap();
// 使用 entry
let record = student_map.entry(name.to_string()).or_insert_with(Student::new);
map.entry(key).or_insert(value) 保证 map 包含键为 key 的条 目,必要时会以给定的默认 value 插入新条目。这个方法返回对 新的或已有值的可修改引用。假设我们要计算投票数。可以这样 写:
let mut vote_counts: HashMap<String, usize> =
HashMap::new();
for name in ballots {
let count = vote_counts.entry(name).or_insert(0);
*count += 1; }
HashSet & BTreeSet
是为快速测试成员关系而组织值的一种集合。
let b1 = large_vector.contains("needle"); // 慢,检查每个元素
let b2 = large_hash_set.contains("needle"); // 快,散列查找
集中永远不会包含同一个值的多个副本
不支持按可修改引用迭代集。没有办法从集中取得值的可修改引用
- 按值迭代(for v in set)产生集的成员(并且消费集)。
- 按共享引用迭代(for v in &set)产生集成员的共享引用。