我很难理解,为什么peek()方法会悄悄地borrow self 的论点.

documentation人说:

"返回对Next()值的引用,而不推进迭代器."

既然它没有推进迭代器,那么将参数borrow 为可变参数背后的意义是什么?

我查看了peek()的实现,注意到它正在调用next()方法.

#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn peek(&mut self) -> Option<&I::Item> {
    let iter = &mut self.iter;
    self.peeked.get_or_insert_with(|| iter.next()).as_ref()
}

是因为使用了next()方法,peek()方法被设计为可变借入,还是peek()方法背后有另一个真正需要可变借入的语义?

换句话说,当调用peek()方法时,发生Mutations 的是什么?

推荐答案

正如您已经做过的,让我们看看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

Rust相关问答推荐

泛型属性比较

go 掉包装 struct 中的泛型

使用元组执行条件分支的正确方法

"value is never read警告似乎不正确.我应该忽略它吗?

在决定使用std::Sync::Mutex还是使用Tokio::Sync::Mutex时,操作系统线程调度是考虑因素吗?

闭包不会发送,即使它只捕获发送变量

RUST应用程序正在退出,错误代码为:(退出代码:0xc0000005,STATUS_ACCESS_VIOLATION)

如何在Rust中基于字符串 Select struct ?

是否提供Bundle 在可执行文件中的warp中的静态文件?

考虑到Rust不允许多个可变引用,类似PyTorch的自动区分如何在Rust中工作?

什么是`&;[][..]`铁 rust 里的刻薄?

使用启用优化的 alloc 会导致非法指令崩溃

tokio::spawn 有和没有异步块

如何从borrow 的异步代码运行阻塞代码?

为什么Rust中无法推断生命周期?

pyO3 和 Panics

为什么拥有 i32 所有权的函数需要它是可变的?

我可以在不调用 .clone() 的情况下在类型转换期间重用 struct 字段吗?

有没有办法使用 NASM 语法进行内联汇编?

如何制作具有关联类型的特征的类型擦除版本?