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

时间:2015-01-11 00:44:55

标签: 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
}

drain&mut带到集合中,之后可以使用该集合。 into_iter使用该集合。每个迭代器的适当用途是什么?

3 个答案:

答案 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