我试图在Rust中使用带有迭代器的模式并在某处掉落,显然很简单 .
我想迭代一个容器并找到一个带有谓词[A](简单)的元素,但是然后使用另一个谓词向前看并得到该值[B]并使用[B]以某种方式改变[A] . 在这种情况下,[A]是可变的,[B]可以是不可变的;这对我没有任何影响,只对借阅检查员(正确) .
通过一个简单的场景来理解这一点很有帮助,所以我添加了一个小片段让民众看到问题/尝试的目标 . 我玩过itertools并进入for / while循环,尽管我希望尽可能保持惯用 .
Silly Example scenario
查找偶数,找到可被3整除的下一个数字并添加到初始数字 .
#[allow(unused)]
fn is_div_3(num: &u8) -> bool {
num % 3 == 0
}
fn main() {
let mut data: Vec<u8> = (0..100).collect();
let count = data.iter_mut()
.map(|x| {
if *x % 2 == 0 {
// loop through numbers forward to next is_div_3,
// then x = x + that number
}
true
})
.count();
println!("data {:?}, count was {} ", data, count);
}
2 回答
Warning: The iterator presented right below is unsafe because it allows one to obtain multiple aliases to a single mutable element; skip to the second part for the corrected version. (如果返回类型包含不可变引用,那就没关系) .
如果您愿意编写自己的窗口迭代器,那么它就变得非常容易了 .
首先,它的所有血腥细节都是迭代器:
在
[1, 2, 3]
上调用它将返回(&[], &[1, 2, 3])
然后(&[1], &[2, 3])
,...直到(&[1, 2, 3], &[])
. 简而言之,它迭代切片的所有潜在分区(不进行混洗) .哪个使用安全:
不幸的是,它也可以用作:
当运行print时:
0x7f73a8435000 0x7f73a8435000
,show-casing两个可变引用别名相同的元素 .由于我们无法摆脱锯齿,我们需要摆脱可变性;或者至少推迟内部可变性(
Cell
,因为u8
是Copy
) .幸运的是,
Cell
没有运行时成本,但它确实在人体工程学方面花费了一些成本(所有那些.get()
和.set()
) .我借此机会使迭代器稍微更通用,并重命名它,因为
Window
已经是另一个概念的已使用名称 .我们将它用作建筑砖:
On the playpen这打印:
[1, 5, 3, 10, 5, 15, 7, 17, 9, 22, ...]
,这似乎是正确的 .可悲的是我有点晚了,但是到了 .
它并不完全漂亮,但它没有其他建议那么糟糕:
给
和Matthieu M.的解决方案一样 .
关键是使用
mut_items.into_slice()
到"reborrow"迭代器,有效地生成迭代器的本地(因此是安全的)克隆 .