我什么时候应该使用`drain` vs`into_iter`?

She*_*ter 15 iterator rust

从表面上看,它看起来像两者draininto_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
}
Run Code Online (Sandbox Code Playgroud)

drain需要&mut收集和收集可用之后.into_iter消耗该集合.每个迭代器的适当用途是什么?

huo*_*uon 14

它们彼此有些多余.但是,如你所说,Drain只是借用向量,特别是它有一个与向量连接的生命周期.如果一个人希望以最灵活的方式返回迭代器,或以其他方式使用迭代器,则使用into_iter更好,因为它不会链接到原始的所有者Vec.如果一个人希望重用数据结构(例如重用分配),那么这drain是最直接的方式.

另外,(某种程度上)理论上的关注是Drain 需要导致原始结构是它的任何类型的有效实例,即,保留不变量,或者在最后修复它们,同时IntoIter可以破坏结构.它喜欢,因为它完全控制了价值.

我只是说"有些"理论,因为现在有一个小的,现实世界的例子std:HashMap暴露.drain.into_iter通过其内部RawTable类型,也有这些方法.into_iter可以只读取直接移动的值的哈希就是这样,但drain必须小心更新哈希以指示该单元格是空的,而不仅仅是读取它.显然这在这种情况下是非常小的(可能只有一两个附加指令)但是对于像树一样的更复杂的数据结构,可能会有一些非平凡的收益来打破数据结构的不变量.


Jan*_*nis 11

对于 2018 版 Rust:

into_iter消耗集合本身,drain仅消耗集合中的值。

因此drain只允许排出集合的一部分,现在实际上需要指定一个范围。(自从提出问题以来,这似乎已经发生了变化。)

因此,into_iter如果您想使用整个集合,请使用它;drain如果您只想使用集合的一部分,或者如果您想稍后重用清空的集合,则请使用。


Fra*_*gné 8

使用后drain,它Vec是空的,但先前为其元素分配的存储仍然是分配的.这意味着,你可以插入新的元素Vec,而无需对他们直到你到达分配存储Vec能力.

请注意,在Vec再次使用之前,必须删除对Drain迭代器的所有引用.Drain执行Drop将删除尚未从中删除的所有元素Vec,因此Vec即使您没有完成迭代,它也将为空.