简体   繁体   English

为什么 Iterator::take_while 获得迭代器的所有权?

[英]Why does Iterator::take_while take ownership of the iterator?

I find it odd that Iterator::take_while takes ownership of the iterator.我觉得Iterator::take_while获得迭代器的所有权很奇怪。 It seems like a useful feature to be able to take the first x elements which satisfy some function but still leave the rest of the elements available in the original iterator.能够获取满足某些功能的前x 个元素,但仍然保留原始迭代器中可用的其余元素,这似乎是一个有用的功能。

I understand that this is incompatible with a lazy implementation of take_while , but still feels useful.我知道这与take_while的惰性实现不兼容,但仍然感觉有用。 Was this just judged not useful enough to include in the standard library, or is there some other problem I'm not seeing?这只是被判断为不足以包含在标准库中,还是有其他一些我没有看到的问题?

All the iterator adapters take the original iterator by value for efficiency's sake.为了效率,所有迭代器适配器都按值采用原始迭代器。 Additionally, taking ownership of the original iterator avoids having to deal with lifetimes when it isn't necessary.此外,获得原始迭代器的所有权可避免在不必要时处理生命周期。

If you wish to retain access to the original iterator, you can use by_ref .如果您希望保留对原始迭代器的访问权限,可以使用by_ref This introduces one level of indirection, but the programmer chooses to opt into the extra work when the feature is needed:这引入了一层间接,但程序员在需要该功能时选择加入额外的工作:

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);
    }
}

Has the output有输出

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

Iterator::by_ref works because there's an implementation of Iterator for any mutable reference to an iterator: Iterator::by_ref有效,是因为对于Iterator的任何可变引用都有Iterator的实现:

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

This means that you can also take a mutable reference.这意味着您还可以采用可变引用。 The parenthesis are needed for precedence:括号需要优先:

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

Did you note that 4 was missing?你有没有注意到4不见了? That's because once take_while picks a value and decides to not use it, there's nowhere for it to "put it back".那是因为一旦take_while选择了一个值并决定不使用它,它就无处可“放回去”。 Putting it back would require opting into more storage and slowness than is always needed.把它放回去需要选择比总是需要的更多的存储和缓慢。

I've used the itertools crate to handle cases like this, specifically take_while_ref :我使用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

If it's getting too complicated, we may be using the wrong tool.如果它变得太复杂,我们可能使用了错误的工具。
Note that 4 is present here.请注意,此处为 4。

fn main() {
    let v = [1, 2, 3, 4, 5, 6, 7, 8];
    let mut i1 = v.iter().peekable();
    while let Some(z) = i1.next_if(|n| n < &&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

Yes, the OP asked for take_while and Shepmaster's solution is superb.是的,OP 要求take_while并且Shepmaster 的解决方案非常棒。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM