为迭代器实现is_empty的规范方法是什么?

时间:2017-08-18 16:41:51

标签: rust

我有一些实现std::iter::Iterator的东西,我想知道是否有> 0个元素。这样做的标准方法是什么? count() > 0看起来太贵了。

我看到两位候选人:any(|_| true)nth(0).is_some(),但我应该选择哪一位,以便将来的读者可以了解我在这里查看的内容?

2 个答案:

答案 0 :(得分:9)

我会写iter.next().is_some()

但是,您需要注意这样做推进迭代器

fn main() {
    let scores = [1, 2, 3];
    let mut iter = scores.iter();

    println!("{}", iter.next().is_some()); // true
    println!("{}", iter.next().is_some()); // true
    println!("{}", iter.next().is_some()); // true
    println!("{}", iter.next().is_some()); // false
}

在很多情况下,我会使用Peekable

fn main() {
    let scores = [1, 2, 3];
    let mut iter = scores.iter().peekable();

    println!("{}", iter.peek().is_some()); // true
    println!("{}", iter.peek().is_some()); // true
    println!("{}", iter.peek().is_some()); // true
    println!("{}", iter.peek().is_some()); // true
}
  

所以未来的读者可以在视线中理解

add a method on iterator命名为is_empty

答案 1 :(得分:5)

is_empty实施Iterator的规范方法不是这样做。 Iteratorthis,因此根据定义,如果没有迭代,就无法知道它是否还有其他元素。

从逻辑上讲,迭代器似乎应该很容易知道它是否还有更多的元素,但如果它的大小已知,则只能是这种情况(没有迭代)。事实上,lazy实现了is_empty

要检查Iterator是否为空,您必须尝试迭代并检查是否收到None,但是(如@Shepmaster所述),您只能在不推进{{Iterator的情况下执行此操作1}}当你有Peekable Iterator时。您可以在下一个元素peek()查看是否is_none()

let mut iterator = vec![1,2,3].into_iter().peekable();
println!("is_empty: {}", iterator.peek().is_none());

在考虑实施Iterator时,这变得更加明显,只需要提供next函数,该函数返回SomeNone以指示是否还有其他元素存在。我们可以提供next的实现来随机决定下一个元素是否存在,这清楚地表明我们无法在不执行next的情况下知道我们的迭代器是否为空:

struct RandomThings {}
impl Iterator for RandomThings {
    type Item = bool;
    fn next(&mut self) -> Option<bool> {
        let has_next = rand::random::<bool>();
        if has_next {Some(true)} else {None}
    }
}

因此,创建Peekable迭代器并调用.peek().is_none()实际上非常明确,未来的读者应该很容易理解。如果您只处理已知大小的迭代器,那么您可以将类型进一步限制为ExactSizeIterator并使用is_empty。如果您要为普通is_empty添加Iterator,则只会隐藏必须调用其next函数以确定它是否为空的事实。