从表面上看,drain
和into_iter
似乎都提供了类似的迭代器,即集合的值。但是,它们是不同的:
fn main() {
let mut items1 = vec![0u8, 1, 2, 3, 4, 5, 6, 7, 8, 9];
let items2 = items1.clone();
println!("{:?}", items1.drain().count());
println!("{:?}", items2.into_iter().count());
println!("{:?}", items1);
// println!("{:?}", items2); Moved
}
drain
将&mut
带到集合中,之后可以使用该集合。 into_iter
使用该集合。每个迭代器的适当用途是什么?
答案 0 :(得分:12)
他们彼此有点多余。但是,如你所说,Drain
只是借用了向量,特别是它有一个与向量相关的生命周期。如果希望以最灵活的方式返回迭代器或以其他方式处理迭代器,则使用into_iter
会更好,因为它不会链接到原始Vec
的所有者。如果一个人希望重用数据结构(例如重用分配),那么drain
是最直接的方式。
另外,(某种程度上)理论上的担忧是Drain
需要导致原始结构是它的任何类型的有效实例,即保留不变量,或者最后修复它们,而IntoIter
可以根据需要修改结构,因为它可以完全控制值。
我只是说“有点”理论,因为std
已经有一个小的,现实世界的例子:HashMap
通过其内部公开.drain
和.into_iter
{ {1}}类型,也有这些方法。 RawTable
可以read the hash of the value being moved directly就是这样,但into_iter
必须小心谨慎to update the hash to indicate that the cell is then empty,而不仅仅是阅读它。显然,在这种情况下这绝对是微不足道的(可能只有一两个附加指令)但是对于像树这样更复杂的数据结构,可能会有一些非常重要的收获来打破数据结构的不变量。
答案 1 :(得分:8)
使用drain
后,Vec
为空,但先前为其元素分配的存储仍保持分配状态。这意味着您可以在Vec
中插入新元素,而无需为其分配存储空间,直到您到达Vec
capacity。
请注意,在再次使用Vec
之前,必须删除对Drain
迭代器的所有引用。 Drain
Drop
的实施将删除尚未从Vec
删除的所有元素,因此Vec
即使是{{1}}也是空的你没有完成迭代。
答案 2 :(得分:0)
对于 2018 版 Rust:
https
使用集合本身,into_iter
只使用集合中的值。
因此 drain
只允许排空集合的一部分,现在实际上需要指定一个范围。 (自从提出问题以来,这似乎发生了变化。)
因此,如果您想使用整个集合,请使用 drain
,如果您只想使用集合的一部分,或者您想稍后重用清空的集合,请使用 into_iter
。