提问人:yesint 提问时间:10/23/2023 更新时间:10/24/2023 访问量:71
在 Rust 中克隆源自 into_iter() 的迭代器的成本?
Cost of cloning iterator originating from into_iter() in Rust?
问:
我试图弄清楚克隆源自 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()
答:
7赞
cafce25
10/23/2023
#1
由于每个 IntoIterator
实现都可以定义自己的迭代器,因此答案是完全取决于 生成的迭代器。type IntoIter: Iterator<Item = Self::Item>;
into_iter
因为它正在克隆内部缓冲区,从它的克隆
实现中可以看出:std::vec::IntoIter
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() } }
评论
0赞
yesint
10/23/2023
谢谢,这澄清了事情!但是,我想知道这种设计的基本原理是什么?既然这是不可变的迭代器,那么是什么阻止了多个副本共享同一个缓冲区?
3赞
Colonel Thirty Two
10/23/2023
@yesint将物品移出 vec,从而阻止从最初存储它们的位置进行访问。如果要让多个迭代器共享同一个存储,请使用 ,这将返回引用。vec.into_iter()
vec.iter()
1赞
cafce25
10/23/2023
@yesint没有什么是一成不变的,它拥有这些物品,这意味着它可以对它们做任何它喜欢的事情。此外,要从中获取物品,它必须是可变的,并且它还将返回拥有的物品。请记住,即使原始绑定是不可变的,您也始终能够更改拥有的项。vec::IntoIter
let mut x = x;
4赞
Chayim Friedman
10/23/2023
#2
它克隆整个缓冲区。本质上等于 ,只是它丢弃了已经迭代过的项。您可以看到代码。vec.clone()
你可以改用 Itertools::tee(),但只有当 itertools::tee()
非常大并且你让两个迭代器都围绕同一个项目时,它才会更有效率,所以没有太大的滞后。甚至它的文档也警告说:Vec
注意:如果迭代器是可克隆的,则最好使用它而不是使用此方法。克隆可能更有效率。
评论