如何从Rust中的Vec中取出物品?

时间:2017-08-21 19:02:40

标签: vector collections rust move-semantics

我想要的是这样的方法:

fn take<T>(vec: Vec<T>, index: usize) -> Option<T>

但是,我找不到这样的方法。我错过了什么吗?或者有一个原因,这实际上是不安全的/无法正确完成。

编辑:这是与Built in *safe* way to move out of Vec<T>?不同的问题 那里的目标是一个remove方法,它没有超出边界访问的恐慌(而是返回一个结果。)这里我正在寻找一个消耗Vec的方法,并返回其中一个元素。上述问题的答案都没有解决我的问题。

编辑2:为了进一步澄清,我正在寻找一种消耗 Vec并返回一个元素的方法,而没有以remove和{{的方式恢复Vec的不变量的开销。 1}}做。

2 个答案:

答案 0 :(得分:7)

你可以这样编写你的函数:

fn take<T>(mut vec: Vec<T>, index: usize) -> Option<T> {
    if vec.get(index).is_none() {
        None
    } else {
        Some(vec.swap_remove(index))
    }
}

这是保证O(1)。

提到使用迭代器的另一种解决方案:

fn take<T>(vec: Vec<T>, index: usize) -> Option<T> {
    vec.into_iter().nth(index)
}

我准备写这个:

  

虽然Iterator::nth()通常是线性时间操作,但是向量上的迭代器会覆盖此方法以使其成为O(1)操作。

但后来我注意到,这只适用于迭代切片的迭代器。将在上面的代码中使用的std::vec::IntoIter迭代器不会覆盖nth()。它已被尝试here,但它似乎并不那么容易。

所以:截至目前,上面的代码是O(n)操作!

答案 1 :(得分:2)

标准库中不存在fn take<T>(vec: Vec<T>, index: usize) -> Option<T>的原因是它通常不是很有用。例如,假设您有一个长度为10的Vec<String>,则意味着丢掉9个字符串并仅使用1.这似乎很浪费。

通常,标准库将尝试提供在最多场景中有用的API,在这种情况下,拥有fn take<T>(vec: &mut Vec<T>, index: usize) -> Option<T>更合乎逻辑。

唯一的问题是如何保留不变量,当然:

  • 可以通过与最后一个元素交换来保存它,这是Vec::swap_remove所做的,
  • 可以通过移动后继元素来保留它,这是Vec::drain所做的。

这些非常灵活,可以适应更具体的场景,例如你的场景。

改编swap_remove

fn take<T>(mut vec: Vec<T>, index: usize) -> Option<T> {
    if index < vec.len() {
        Some(vec.swap_remove(index))
    } else {
        None
    }
}

改编drain

fn take<T>(mut vec: Vec<T>, index: usize) -> Option<T> {
    if index < vec.len() {
        vec.drain(index..index+1).next()
    } else {
        None
    }
}

注意前者更有效:它是O(1)。

  

为了进一步说明,我正在寻找一种消耗Vec并返回一个元素的方法,而没有像Vec和{{{{}}}那样恢复remove不变量的开销。 1}}做。

这对我来说是过早的微观优化。

首先,请注意有必要销毁向量的元素;你可以通过两种方式实现这一目标:

  1. swap_remove,然后迭代每个元素以销毁它们,
  2. 遍历每个元素以销毁它们,跳过特定的swap_remove
  3. 我不清楚后者会比前者更快;如果它看起来更复杂,有更多的分支(我建议两个循环),这可能会抛弃预测器,可能不太适合矢量化。

    其次,在抱怨恢复index的不变量的开销之前,你有没有正确地描述解决方案?

    如果我们查看Vec变体,则有3个步骤:

    1. swap_remove(O(1)),
    2. 销毁每个剩余的元素(O(N)),
    3. 释放后备记忆。
    4. 如果元素没有swap_remove实现,则可以优化步骤2,但否则我将是抛出是否(2)或(3)支配成本。

      TL; DR :在尝试优化之前,我担心你会遇到幽灵问题个人资料