Rust固定容量向量库fixed-capacity-vec的使用:高效内存管理下的定长数组解决方案
Rust固定容量向量库fixed-capacity-vec的使用:高效内存管理下的定长数组解决方案
FixedCapacityVec
是一个简单的特殊用途数据结构,主要用于需要逐步构建固定大小表格的应用场景。
与标准库类型的比较
以下所有类型都只在堆上存储实际缓冲区,并且可以在不复制数据的情况下相互转换:
类型 | 大小和表示形式(如在栈上) | 是否总是满的 | 可变性 |
---|---|---|---|
Vec |
3个字:指针、长度、容量 | 可能 | 可无限追加 |
Box<[T]> |
2个字:指针、长度=容量 | 总是 | 运行时固定长度 |
FixedCapacityVec<T, N> |
2个字:指针、长度 | 可能 | 可追加,但容量在编译时固定 |
Box<[T; N]> |
1个字:指针 | 总是 | 编译时固定长度 |
内存布局示意图:
Vec<T> HEAP Box<[T]> HEAP
+----------+ +------------+ +----------+ +----------+
| pointer ----> | T | | pointer ----> | T |
| length | | T ... | | length | | T ... |
| capacity | +--length----+ +----------+ +--length--+
+----------+ | (spare) |
+--capacity--+
FixedCapacityVec<T, N> HEAP Box<[T; N]> HEAP
+----------+ +-------------+ +----------+ +---------+
| pointer ----> | T | | pointer ----> | T |
| length | | T ... | +----------+ | T ... |
+----------+ |--length-----| +--N------+
| (spare) |
+--N----------|
与其他库的vec-like类型的比较
FixedCapacityVec
与ArrayVec
和SmallVec
有不同的用途。
FixedCapacityVec
的数据总是存储在堆上。
相比Vec
,FixedCapacityVec
的优势在于:
- 自身尺寸更小
- 不需要表示或查找容量
- 可以非常廉价地转换为装箱数组、
Vec
或装箱切片,无需复制
ArrayVec
也是一个固定容量的vec-like结构,但它的数据与元数据存储在一起。要将一个满的ArrayVec
转换为装箱数组,必须复制数据。
SmallVec
的优势在于可以在栈上存储少量数据,但SmallVec
本身并不特别小。
完整示例代码
use fixed_capacity_vec::FixedCapacityVec;
fn main() {
// 创建一个容量为5的FixedCapacityVec
let mut fcv: FixedCapacityVec<i32, 5> = FixedCapacityVec::new();
// 添加元素
fcv.push(1);
fvc.push(2);
fvc.push(3);
println!("Length: {}, Capacity: {}", fcv.len(), fcv.capacity()); // 长度:3, 容量:5
// 转换为Box<[i32; 5]>
let boxed_array: Box<[i32; 5]> = fcv.into_boxed_array().unwrap();
// 转换为Vec
let vec: Vec<i32> = boxed_array.into_vec();
println!("Vec: {:?}", vec);
}
这个示例展示了如何:
- 创建一个固定容量的向量
- 向其中添加元素
- 将其转换为装箱数组
- 再转换为普通Vec
所有转换都不需要复制实际数据。
扩展完整示例代码
use fixed_capacity_vec::FixedCapacityVec;
fn main() {
// 1. 创建固定容量为10的向量
let mut fcv: FixedCapacityVec<String, 10> = FixedCapacityVec::new();
// 2. 添加元素
for i in 0..7 {
fcv.push(format!("Item-{}", i));
}
// 3. 检查长度和容量
println!("当前长度: {}, 固定容量: {}", fcv.len(), fcv.capacity());
// 4. 访问元素
println!("第一个元素: {}", fcv[0]);
println!("最后一个元素: {}", fcv.last().unwrap());
// 5. 转换为Box<[String; 10]>
match fcv.into_boxed_array() {
Ok(boxed_array) => {
println!("转换为Box<[String; 10]>成功");
// 6. 转换为Vec
let vec: Vec<String> = boxed_array.into_vec();
println!("Vec内容: {:?}", vec);
}
Err(fcv) => {
println!("转换失败,当前长度: {}", fcv.len());
}
}
// 7. 错误处理示例
let mut small_fcv: FixedCapacityVec<i32, 3> = FixedCapacityVec::new();
small_fcv.push(1);
small_fcv.push(2);
// 尝试转换为数组切片
if let Ok(slice) = small_fcv.as_slice() {
println!("切片内容: {:?}", slice);
}
// 尝试转换为可变切片
if let Ok(mut_slice) = small_fcv.as_mut_slice() {
mut_slice[1] = 99;
println!("修改后的可变切片: {:?}", mut_slice);
}
}
这个扩展示例展示了:
- 创建带有String类型的FixedCapacityVec
- 批量添加元素
- 访问元素的各种方式
- 转换时的错误处理
- 切片操作的使用
- 更完整的类型转换流程
1 回复