Vector 如何从锈迹斑斑的Vec中取出物品?

Vector 如何从锈迹斑斑的Vec中取出物品?,vector,collections,rust,move-semantics,Vector,Collections,Rust,Move Semantics,我正在寻找一种方法,使用Vec并返回一个元素,而不需要像remove和swap\u remove那样恢复Vec的不变量: fn take<T>(vec: Vec<T>, index: usize) -> Option<T> fn-take(vec:vec,index:usize)->选项 然而,我找不到这样的方法。我错过什么了吗?这实际上是不安全的还是不可能的 这是一个与之不同的问题 这里的目标是一个remove方法,它不会在越界访问时惊慌失措,并返

我正在寻找一种方法,使用
Vec
并返回一个元素,而不需要像
remove
swap\u remove
那样恢复
Vec
的不变量:

fn take<T>(vec: Vec<T>, index: usize) -> Option<T>
fn-take(vec:vec,index:usize)->选项
然而,我找不到这样的方法。我错过什么了吗?这实际上是不安全的还是不可能的

这是一个与之不同的问题
这里的目标是一个
remove
方法,它不会在越界访问时惊慌失措,并返回一个
结果
。我正在寻找一个使用
Vec
并返回其中一个元素的方法。上述问题的答案都不能回答我的问题。

您可以这样编写函数:

fn take<T>(mut vec: Vec<T>, index: usize) -> Option<T> {
    if vec.get(index).is_none() {
        None
    } else {
        Some(vec.swap_remove(index))
    }
}
我正要写这封信:

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

但后来我注意到,这只适用于在片上迭代的迭代器。上述代码中使用的
std::vec::IntoIter
迭代器不会覆盖
nth()
。已经尝试过了,但似乎没有那么容易

因此,到目前为止,上面的迭代器解决方案是一个O(n)操作!更不用说删除向量所需的时间了,如上所述。

标准库中不存在选项的原因是它通常不是很有用。例如,假设有一个长度为10的
Vec
,这意味着扔掉9个字符串,只使用1个。这似乎是浪费

一般来说,标准库将尝试提供在最多情况下都有用的API,在这种情况下,使用
fn take(vec:&mut-vec,index:usize)->选项将更符合逻辑

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

  • 它可以通过与最后一个元素交换来保存,这就是
    Vec::swap\u remove
    所做的
  • 它可以通过在中移动后续元素来保留,这就是
    Vec::drain
    所做的
这些都是非常灵活的,可以适应更具体的场景,比如你的场景


调整
swap\u remove

fn take<T>(mut vec: Vec<T>, index: usize) -> Option<T> {
    if index < vec.len() {
        Some(vec.swap_remove(index))
    } else {
        None
    }
}
注意到前者更有效:它是O(1)


我正在寻找一种使用
Vec
并返回一个元素的方法,而不需要像
remove
swap\u remove
那样恢复
Vec
的不变量

对我来说,这意味着过早的微观优化

首先,要注意的是要破坏向量的元素;您可以通过两种方式完成此任务:

  • swap\u remove
    ,然后迭代每个元素以销毁它们
  • 迭代每个元素以销毁它们,跳过特定的
    索引
  • 我不清楚后者是否比前者快;如果它看起来更复杂,有更多的分支(我建议使用两个循环),这可能会丢掉预测器,并且不太适合矢量化

    其次,在抱怨恢复
    Vec
    不变量的开销之前,您是否正确地分析了解决方案

    如果我们看一下
    swap\u remove
    变体,有3个步骤:

  • swap_remove
    (O(1))
  • 销毁每个剩余元素(O(N))
  • 释放备份内存
  • 如果元素没有
    Drop
    实现,那么第2步可能会被优化掉,但是如果不是这样的话,我会怀疑(2)或(3)是否会主导成本


    TL;DR:我担心您正在与鬼问题作斗争,配置文件在尝试优化之前。

    您的具体意思是
    选项
    ,而不是
    选项
    ,您可以从
    vec.get(index)
    获得它,或者你错过了
    .get
    存在吗?@loganfsmyth我特别指的是
    选项
    ,就像我在问题中说的那样。我想要的类似于
    选项。take()
    如果这有意义吗?注意:如果你发现自己定期抛出
    Vec
    ,你可能想看看是否可以避免从一开始就具体化它们。不做任何事总是比做某件事快,不管你做得多么有效率。啊,这是一个有点丑陋的解决方案,但我认为它应该有效!我仍然认为在Vec上使用
    take
    方法会很好…@其他人也许你应该在第一个解决方案中将
    mut-Vec:Vec
    更改为
    Vec:&mut-Vec
    ?OP明确地问了一些消耗向量的问题。我不一定只抱怨恢复向量不变量的开销(尽管我正在处理的代码是在一个紧密的内部循环中,所以速度对我来说确实很重要),我还想编写符合我意思的代码。在本例中,我真正想要表达的是
    take
    操作,而不是
    remove
    操作。即使这只是一个速度问题,我也需要一个替代方案来对抗任何情况。@Others:“紧密的内部循环”和“丢弃
    Vec
    ”听起来不太好。一旦您编写了代码,我鼓励您将其发布到代码评论或reddit,并询问如何优化它;希望有一种方法可以避免内部循环中的内存释放,因为这样做代价高昂。
    fn take<T>(mut vec: Vec<T>, index: usize) -> Option<T> {
        if index < vec.len() {
            Some(vec.swap_remove(index))
        } else {
            None
        }
    }
    
    fn take<T>(mut vec: Vec<T>, index: usize) -> Option<T> {
        if index < vec.len() {
            vec.drain(index..index+1).next()
        } else {
            None
        }
    }