【问题标题】:When should I use `drain` vs `into_iter`?我什么时候应该使用`drain` vs`into_iter`?
【发布时间】:2015-03-09 02:04:48
【问题描述】:

从表面上看,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 使用该集合。每个迭代器的适当用途是什么?

【问题讨论】:

    标签: iterator rust


    【解决方案1】:

    它们彼此有些多余。但是,正如您所说,Drain 只是借用了向量,特别是,它与向量具有生命周期。如果希望返回一个迭代器,或者以最灵活的方式处理迭代器,使用into_iter 更好,因为它没有链接到原始Vec 的所有者。如果希望重用数据结构(例如重用分配),那么drain 是最直接的方法。

    另外,一个(有点)理论上的担忧是Drain需要导致原始结构成为任何类型的有效实例,也就是说,要么保留不变量,要么修复它们最后,IntoIter 可以随意修改结构,因为它可以完全控制值。

    我只说“有点”理论上的,因为在 std 中已经有一个小的真实世界示例:HashMap 通过其内部 RawTable 类型公开了 .drain.into_iter,其中也有这些方法。 into_iter 可以只是 read the hash of the value being moved directly 就是这样,但 drain 必须小心 to update the hash to indicate that the cell is then empty,而不仅仅是阅读它。显然,在这种情况下这绝对是很小的(可能只有一两条额外的指令),但对于更复杂的数据结构,如树,可能会从打破数据结构的不变量中获得一些不平凡的收益。

    【讨论】:

    • 似乎.drain for HashMap 会导致清除原始结构,并且它不能在结构的子集上工作。那么有效有什么区别? drain 不取得所有权,但导致原始结构被清除,.into_iter 取得所有权,因此原始结构无法使用并被保留为空壳?
    • 如果vector在struct中,不能简单地将vec转换成iterator it;您将需要为结构实现 IntoIterator,或耗尽向量。
    【解决方案2】:

    使用drain 后,Vec 为空,但之前为其元素分配的存储仍保持分配状态。这意味着您可以在Vec 中插入新元素,而无需为它们分配存储空间,直到到达Veccapacity

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

    【讨论】:

    【解决方案3】:

    对于 2018 年版的 Rust:

    into_iter 消费集合本身,drain 只消费集合中的值。

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

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

    【讨论】:

      猜你喜欢
      • 2021-12-19
      • 2019-11-04
      • 2019-08-14
      • 1970-01-01
      • 1970-01-01
      • 2011-03-11
      • 1970-01-01
      • 1970-01-01
      • 2021-09-07
      相关资源
      最近更新 更多