问题描述
我有一个自定义迭代器,我想在自定义 .skip(...)
方法中选择性地调用 .next()
。但是,我收到类型错误,因为 Skip != Iterator
。
示例代码如下:
struct CrossingIter<'a,T> {
index: usize,iter: std::slice::Iter<'a,T>,}
impl<'a,T: Float> Iterator for CrossingIter<'a,T> {
type Item = (usize,T);
fn next(&mut self) -> Option<(usize,T)> {
let iter = (&mut self.iter).enumerate();
let iter = if self.index == 0 {
self.index += 3;
iter.skip(3)
} else {
iter
}
// lots of code here working with the new iterator
iter.next()
}
}
问题是调用 .skip(3)
后,iter
的类型发生了变化。一种解决方案是在 // lots of code ...
语句的每个分支中复制 if
,但我不想这样做。
我的问题是:有没有办法有条件地将 skip(...)
应用于迭代器并继续使用它而不复制一堆代码?
解决方法
skip
旨在构造一个新的迭代器,这在您希望代码至少在表面上保持不变的情况下非常有用。但是,在您的情况下,您希望推进现有 迭代器,同时仍保持其有效。
有 advance_by
可以做你想做的事,但它是 Nightly,所以它不会在稳定的 Rust 上运行。
if self.index == 0 {
self.index += 3;
self.iter.advance_by(3);
}
我们可以滥用 nth
来获得我们想要的东西,但这不是很惯用。
if self.index == 0 {
self.index += 3;
self.iter.nth(2);
}
如果我在生产环境中看到该代码,我会很困惑。
最简单且不太令人满意的答案是将 advance_by
重新实现为辅助函数。 The source 可用且很容易适应
fn my_advance_by(iter: &mut impl Iterator,n: usize) -> Result<(),usize> {
for i in 0..n {
iter.next().ok_or(i)?;
}
Ok(())
}
所有这一切,如果您的用例实际上只是跳过前三个元素,您需要的只是从 skip
调用开始并假设您的迭代器始终是 { {1}}
Skip
,
我认为@Silvio 的回答是一个更好的视角。
您可以在 skip(0)
分支中调用 iter
而不是 else
本身...
并且 enumerate
生成的迭代器的返回值与您的定义不匹配:fn next(&mut self) -> Option<(usize,T)>
。你需要映射它。
这是一个工作示例:
use num::Float;
struct CrossingIter<'a,T> {
index: usize,iter: std::slice::Iter<'a,T>,}
impl<'a,T: Float> Iterator for CrossingIter<'a,T> {
type Item = (usize,T);
fn next(&mut self) -> Option<(usize,T)> {
let iter = (&mut self.iter).enumerate();
let mut iter = if self.index == 0 {
self.index += 3;
iter.skip(3)
} else {
iter.skip(0)
};
// lots of code here working with the new iterator
iter.next().map(|(i,&v)| (i,v))
}
}