是否有任何理由不将DoubleEndedIterator用于不迭代一系列事物的迭代器?

Adr*_*ian 6 rust

据我所知,它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);
    }
}
Run Code Online (Sandbox Code Playgroud)

所以这是我的问题:使用DoubleEndedIterator这种方式有什么语义错误吗?是否有某种原因使用它的目的与文档所说的不同?还有,有更好的方法来实现同样的目的吗?

blu*_*uss 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
}
Run Code Online (Sandbox Code Playgroud)

这显示了一个表现良好的双端迭代器是什么样的.(防锈围栏链接)


现在,对于DoubleEndedIterator"滥用" 的问题:

这是有问题的.

DoubleEndedIterator文档是明确的:

范围迭代器,能够从两端生成元素

A DoubleEndedIterator可以被认为是其中的双端齿轮next()next_back() 来自相同范围的排气元件,并且不能彼此独立地工作.

您必须将其理解为:无论是否使用next,next_back或者它们的组合,如果您跟踪它们(并跟踪它们来自哪个端点),任何遍历都必须生成相同范围的元素.

但是,有无限范围的情况......

在无限长的范围内,两端永远不会相遇.这种迭代器的一个例子是repeat.对于这个简单的例子可以很容易地看到二者为什么迭代器是无限的,怎么都next()next_back()在逻辑上定义.

所以这是一个漏洞,您可以将迭代器的序列指定为无限长,尽管双重结束.我认为用我们的固定位宽整数来正确地实现这个接口是值得怀疑的.

即使有可疑的哲学动机,它也可能是一个非常混乱的迭代器,它无视合理的期望.我认为使用特征错误(比如说有一个迭代器的两个完全不同意的结尾)会很糟糕,但是如果有一个取之不尽的范围,你实际上不会破坏任何特征属性.