1 个不稳定版本
0.1.0 | 2023 年 6 月 19 日 |
---|
#1677 in Rust 模式
26KB
338 行
Handlevec
在遍历向量时,对索引风格的抽象,支持在迭代过程中进行删除、插入等操作。希望这比手动考虑索引更新更少出现错误和头痛。
简单示例
use handlevec::mutate_vec_by_handles;
let mut my_vec = vec![1, 4, 9, 16, 25, 36, 49, 64, 81, 100];
mutate_vec_by_handles(&mut my_vec, |mut elem| {
// Get and copy the next element, if it exists (it must be copied because of the borrow checker.)
if let Some(n) = elem.peek_forward_slice(1).copied() {
*elem.get_mut() *= n; // Multiply this element by the next element, in-place.
} else {
elem.discard(); // Discard this element if there is no next element
}
});
assert_eq!(my_vec, vec![4, 36, 144, 400, 900, 1764, 3136, 5184, 8100]);
// Or you can add it as a trait extension, if preferred:
use handlevec::VecMutateByHandles;
my_vec.mutate_vec_by_handles(|mut element| {
if *element.get() == 900 {
element.insert_and_skip(50);
}
});
assert_eq!(my_vec, vec![4, 36, 144, 400, 900, 50, 1764, 3136, 5184, 8100]);
使用 while 循环的示例,如果你不喜欢闭包
use handlevec::VecMutationHandle;
let mut my_vec = vec![2, 3, 4, 5, 6, 11, 1, 5, 7];
let mut my_index = 0;
while let Some(mut elem) = VecMutationHandle::new(&mut my_vec, &mut my_index) {
if *elem.get() > 10 {
elem.discard_and_stop_iteration();
} else {
elem.set(20);
}
}
assert_eq!(my_vec, vec![20, 20, 20, 20, 20, 1, 5, 7]);
对于这些示例中的大多数,可能最好使用正常的迭代器,比如 flatmap 或 filter 或 map。这里考虑的特定用例是,如果你有一个更复杂数据类型的向量,其中各种情况可能需要非常不同的处理。
请注意,此包根本不尝试“缓冲”对向量所做的更改。更改是在函数调用时应用的。对于长向量以及大量插入或删除,每次迭代后重新组织向量可能效率不高。
这确实包含 unwraps,但它们绝对不应该通过任何公共 API 的输入访问。如果你从这个 crate 中收到 panic,非常感谢提交错误报告。
功能
- 使用上述方法之一(它们是等效的)遍历向量,并对每个元素
- 获取当前元素的(可能可变)引用。
- 将新值设置到当前元素。
- 丢弃当前元素(并返回对该元素的拥有权,但不能对此元素应用其他操作。)
- 在当前元素之后插入一个元素,并在下一次迭代中处理它。
- 在当前元素之后插入一个元素,但不在下一次迭代中处理它。
- 跳过处理特定数量的元素。
- 停止迭代。闭包或循环的其余部分仍然执行,因为方法必须返回,但不能处理更多元素。
- 丢弃当前元素,并停止迭代。discard 和 stop_iteration 方法都消耗拥有权,因此提供此方法,如果您想同时进行这两项操作。
- “查看”向量的一个(可能可变)引用的切片,其中 0 是当前元素的索引。例如,
1
是下一个元素,而0..
是包括此元素在内的剩余元素切片。 - 按正确顺序插入多个元素。(多次调用 insert 会反转插入元素顺序,类似于堆栈的 push。)
- 将特定位置的元素替换为另一个元素。
- 最后,闭包是一个
FnMut
,因此内部循环可以影响闭包之外的可变变量。按照设计,不允许在当前元素之前修改或获取元素。