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
}
}