我发现Iterator::take_while拥有迭代器的所有权是很奇怪的,它似乎是一个有用的特性,能够获取满足某个函数的前 x 个元素,但仍然保留原始迭代器中可用的其余元素。 我知道这与take_while的惰性实现不兼容,但仍然感觉很有用,这是因为它被认为没有足够的用处而不能包含在标准库中,还是有其他我没有看到的问题?
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,
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
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
2条答案
按热度按时间3wabscal1#
为了效率起见,所有的迭代器适配器都是按值获取原始迭代器的,另外,获取原始迭代器的所有权避免了在不必要的时候处理生存期。
如果你想保留对原始迭代器的访问,你可以使用
by_ref
,这引入了一个间接层,但是当需要这个特性时,程序员会选择加入额外的工作:具有输出
Iterator::by_ref
之所以有效,是因为Iterator
实现了对迭代器的任何可变引用:这意味着你也可以接受一个可变的引用。括号的优先级是必需的:
你注意到
4
丢失了吗?这是因为一旦take_while
选择了一个值并决定不使用它,它就没有地方可以“放回”了。放回它将需要选择比总是需要的更多的存储和缓慢。我使用itertools crate来处理类似的情况,特别是
take_while_ref
:jv4diomz2#
如果它变得太复杂,我们可能用错了工具。
请注意,此处存在4。
Playground
是的,OP要求
take_while
和Shepmaster's solution是一流的。