Rust中从into_iter()克隆迭代器的成本是多少?

4
我正在试图弄清楚在Rust中从into_iter()产生的迭代器的克隆成本是多少,但是找不到任何有意义的信息。
考虑以下代码:
let v = vec![1,2,3,4,...]; // Some large vector
let iter = v.into_iter().map(...some closure...);
let another_iter = iter.clone(); // What is copied here??

自从我将向量转换为迭代器后,iter现在拥有包含向量值的内部缓冲区。这正是我想要实现的,以抽象容器类型。

然而,当我调用iter.clone()时会发生什么?它会复制整个包含数据的内部缓冲区(可能非常昂贵),还是只复制迭代器状态并引用相同的缓冲区(廉价)?

有没有一种惯用的方法来存储并廉价地克隆由into_iter()生成的这种迭代器?

2个回答

7
每个IntoIterator实现都可以定义自己的type IntoIter: Iterator<Item = Self::Item>;所以答案完全取决于由into_iter产生的迭代器。
对于std::vec::IntoIter来说,它会克隆内部缓冲区,可以通过它的Clone实现看到。
impl<T: Clone, A: Allocator + Clone> Clone for IntoIter<T, A> {
    #[cfg(not(test))]
    fn clone(&self) -> Self {
        self.as_slice().to_vec_in(self.alloc.deref().clone()).into_iter()
    }
    #[cfg(test)]
    fn clone(&self) -> Self {
        crate::slice::to_vec(self.as_slice(), self.alloc.deref().clone()).into_iter()
    }
}

谢谢,这澄清了事情!不过,我想知道这种设计的理念是什么?由于这是不可变迭代器,是什么阻止了多个副本共享同一个缓冲区? - undefined
3
vec.into_iter()从vec中将项目移出,这样就无法从原始存储位置访问它们。如果您希望多个迭代器共享相同的存储空间,请使用vec.iter(),它返回引用。 - undefined
1
@yesint,vec::IntoIter并没有什么是固定不变的,它拥有这些项,这意味着它可以随意处理它们。此外,要从中获取项,它必须是可变的,并且它也会返回拥有的项。请记住,即使原始绑定是不可变的,您始终可以使用let mut x = x;来使拥有的项可变。 - undefined

4

它克隆整个缓冲区。基本上等同于vec.clone(),只是它丢弃已经迭代过的项目。你可以查看代码

你可以使用Itertools::tee(),但只有在Vec非常大且保持两个迭代器在同一项周围时,它才更有效率,这样就不会有很大的延迟。即使它的文档也警告:

注意:如果迭代器是可克隆的,请优先使用它而不是使用此方法。克隆可能更高效。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接