代码之家  ›  专栏  ›  技术社区  ›  m00am

在调用iterator::take之后,有没有办法耗尽迭代器?[副本]

  •  2
  • m00am  · 技术社区  · 6 年前

    我觉得奇怪 Iterator::take_while 取得迭代器的所有权。这似乎是一个有用的功能,能够采取第一 满足某些函数但仍保留原始迭代器中可用的其余元素的元素。

    我知道这与 take_while ,但仍然觉得有用。这是不是被认为不够有用,不足以包含在标准库中,还是有其他问题我没有看到?

    0 回复  |  直到 7 年前
        1
  •  31
  •   Shepmaster Tim Diekmann    4 年前

    为了提高效率,所有迭代器适配器都按值获取原始迭代器。此外,获得原始迭代器的所有权可以避免在不需要时处理生存期。

    如果希望保留对原始迭代器的访问,可以使用 by_ref . 这引入了一个间接层次,但是程序员选择在需要特性时进行额外的工作:

    fn main() {
        let v = [1, 2, 3, 4, 5, 6, 7, 8];
        let mut i1 = v.iter();
        for z in i1.by_ref().take_while(|&&v| v < 4) {
            //     ^^^^^^^^^
            println!("Take While: {}", z);
        }
    
        for z in i1 {
            println!("Rest: {}", z);
        }
    }
    

    有输出

    Take While: 1
    Take While: 2
    Take While: 3
    Rest: 5
    Rest: 6
    Rest: 7
    Rest: 8
    

    Iterator::by_ref 因为有一个 Iterator 对于迭代器的任何可变引用:

    impl<'_, I> Iterator for &'_ mut I
    where
        I: Iterator + ?Sized, 
    

    这意味着您还可以采用可变引用。优先顺序需要括号:

    for z in (&mut i1).take_while(|&&v| v < 4)
    

    你注意到了吗 4 他失踪了?那是因为有一次 take_while 选择一个值并决定不使用它,它没有地方“放回去”。把它放回去需要选择 更多 存储和速度比通常需要的慢。

    我用过 itertools crate 专门处理这样的案子 take_while_ref :

    use itertools::Itertools; // 0.9.0
    
    fn main() {
        let v = [1, 2, 3, 4, 5, 6, 7, 8];
        let mut i1 = v.iter();
        for z in i1.take_while_ref(|&&v| v < 4) {
            //     ^^^^^^^^^^^^^^^
            println!("Take While: {}", z);
        }
    
        for z in i1 {
            println!("Rest: {}", z);
        }
    }
    
    Take While: 1
    Take While: 2
    Take While: 3
    Rest: 4
    Rest: 5
    Rest: 6
    Rest: 7
    Rest: 8