据我了解,DoubleEndedIterator
适用于迭代一系列项目并可从任一端开始的迭代器。例如,(1..10)
可以实现这一点,从1到10,或从10到1。但是,我有一种情况,将此特征用于不迭代的迭代器是有用的在一系列事物上,但可以从同一个位置前进或后退,如下:
struct ExtremeIterator {
number: i32
}
impl Iterator for ExtremeIterator {
type Item = i32;
fn next(&mut self) -> Option<i32> {
let result = self.number;
self.number += 1;
Some(result)
}
}
impl DoubleEndedIterator for ExtremeIterator {
fn next_back(&mut self) -> Option<i32> {
let result = self.number;
self.number -= 1;
Some(result)
}
}
fn main() {
let iter = ExtremeIterator { number: 10 };
for i in iter.rev().take(5) {
println!("{}", i);
}
}
所以这是我的问题:使用DoubleEndedIterator
这种方式有什么语义错误吗?是否有某种原因使用它的目的与文档所说的不同?还有,有更好的方法来实现同样的目标吗?
答案 0 :(得分:9)
首先,让我们在你的问题中澄清这句话:
例如,(1..10)可以实现此功能,可以从1到10,或从10到1。
1..10
的类型为std::ops::Range<T>
,无论您是否迭代,它都会迭代到 1,2,3,4,5,6,7,8,9 <序列从后面或前面。从后面开始,你会得到 9,8,... , 1,2,... ;它是一个开始包容,最终排他范围,也称为半开范围。
如果你要从前面然后从后面迭代一下这个范围,那么它会在两端相遇的地方停止:
let mut range = 1..10;
for i in &mut range {
// Produce 1, 2, 3, 4, 5
// then break.
if i == 5 { break; }
}
for j in range.rev() {
// Produces 9, 8, 7, 6
}
这表明一个表现良好的双端迭代器是什么样的。 (rust playpen link)
现在,关于DoubleEndedIterator
“虐待”的问题:
这是有问题的。
DoubleEndedIterator documentation很清楚:
能够从两端产生元素的范围迭代器
DoubleEndedIterator
可以被认为是来自同一范围的next()
和next_back()
排气元素中的双端队列,并且不会彼此独立地工作。强>
您必须将其理解为:无论使用next
,next_back
还是其中的组合,任何遍历都必须生成相同范围的元素(如果您跟踪它们)(并跟踪哪些元素)结束他们来自。)
然而,存在无限范围的情况......
在无限长的范围内,两端永远不会相遇。这种迭代器的一个例子是repeat
。对于这个简单的例子,很容易理解为什么迭代器是无限的,以及next()
和next_back()
如何在逻辑上定义。
所以这是一个漏洞,您可以将迭代器的序列指定为无限长,尽管双重结束。我认为用我们的固定位宽整数来正确地实现这个接口是值得怀疑的。
即使有可疑的哲学动机,它也可能是一个非常混乱的迭代器,它无视合理的期望。我认为使用特征错误(比如说迭代器有两个完全不同意的结果)会很糟糕,但是在取之不尽的范围内,你实际上并没有打破任何特质属性。