【问题标题】:What is the canonical way to implement is_empty for Iterator?为 Iterator 实现 is_empty 的规范方法是什么?
【发布时间】:2018-01-27 10:02:44
【问题描述】:

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

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

【问题讨论】:

    标签: rust


    【解决方案1】:

    我会写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

    【讨论】:

    • 总结:let is_empty = scores.iter().peekable().peek().is_none();.
    【解决方案2】:

    Iterator 实现is_empty 的规范方法不是这样做。 Iteratorlazy,因此根据定义,如果不进行迭代,它就无法知道它是否还有更多元素。

    从逻辑上讲,Iterator 似乎应该很容易知道它是否还有更多元素,但只有在已知其大小的情况下才会出现这种情况(不进行迭代)。事实上,ExactSizeIterator 实现了is_empty

    要检查Iterator 是否为空,您必须尝试迭代并检查是否收到None,但是(如@Shepmaster 所述),您只能在没有推进Iterator 的情况下这样做一个PeekableIterator。您可以在下一个元素处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。如果您要为普通的Iterator 添加is_empty,您只会隐藏必须调用其next 函数以确定它是否为空的事实。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-06-09
      • 2018-08-05
      • 2020-03-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多