正如您已经做过的,让我们看看its source,它揭示了它是如何在内部工作的:
pub struct Peekable<I: Iterator> {
iter: I,
/// Remember a peeked value, even if it was None.
peeked: Option<Option<I::Item>>,
}
连同其next()
年的实施情况:
impl<I: Iterator> Iterator for Peekable<I> {
// ...
fn next(&mut self) -> Option<I::Item> {
match self.peeked.take() {
Some(v) => v,
None => self.iter.next(),
}
}
// ...
}
它将在peek()
年内实施:
impl<I: Iterator> Peekable<I> {
// ...
pub fn peek(&mut self) -> Option<&I::Item> {
let iter = &mut self.iter;
self.peeked.get_or_insert_with(|| iter.next()).as_ref()
}
// ...
}
Peek wraps是一个现有的迭代器.并且现有的迭代器是不可窥视的.
因此,Peek所做的是:
- On
peek()
:
- 从包装迭代器中取出
next()
项并将其存储在self.peeked
中(如果self.peeked
尚未包含下一项)
- 返回对已查看项的引用
- On
next()
:
- 查看我们当前是否有
self.peeked
个项目
- 如果是,则返回那个
- 如果不是,则从基础迭代器中获取
next()
项.
因此,正如您已经意识到的,peek()
操作需要&mut self
,因为它可能需要通过在底层迭代器上调用next()
来生成下一个窥视的项.
因此,如果你从更抽象的Angular 来看,原因是:下一项可能甚至还不存在.因此,peeking
可能涉及实际生成下一项,这肯定是底层迭代器上的变异操作.
并非所有迭代器都位于项已经存在的数组/片上;迭代器可以由生成许多项的任何东西组成,包括只在请求时创建所述项的懒惰生成器.
他们会不会以不同的方式实施呢?
是的,绝对有可能以不同的方式行事.他们本可以在new()
期间对底层迭代器执行next()
次.然后,当有人在Peekable
上调用next()
时,它可以返回当前查看的值,并立即查询下一个值.然后,偷看就是&self
种方法了.
他们为什么走这条路还不清楚,但最肯定的是让迭代器尽可能地懒惰.在大多数情况下,懒惰迭代器是一件好事.
这就是说,这里是一个概念证明,如何实现预取可窥视迭代器,而不需要peek()
的&mut
:
pub struct PrefetchingPeekingIterator<I: Iterator> {
iter: I,
next_item: Option<I::Item>,
}
impl<I: Iterator> PrefetchingPeekingIterator<I> {
fn new(mut iter: I) -> Self {
let next_item = iter.next();
Self { iter, next_item }
}
fn peek(&self) -> Option<&I::Item> {
self.next_item.as_ref()
}
}
impl<I: Iterator> Iterator for PrefetchingPeekingIterator<I> {
type Item = I::Item;
fn next(&mut self) -> Option<Self::Item> {
std::mem::replace(&mut self.next_item, self.iter.next())
}
}
fn main() {
let mut range = PrefetchingPeekingIterator::new(1..10);
dbg!(range.next().unwrap());
dbg!(range.peek().unwrap());
dbg!(range.next().unwrap());
dbg!(range.peek().unwrap());
dbg!(range.next().unwrap());
dbg!(range.peek().unwrap());
}
[src/main.rs:27] range.next().unwrap() = 1
[src/main.rs:28] range.peek().unwrap() = 2
[src/main.rs:29] range.next().unwrap() = 2
[src/main.rs:30] range.peek().unwrap() = 3
[src/main.rs:31] range.next().unwrap() = 3
[src/main.rs:32] range.peek().unwrap() = 4