标准库中不存在
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
并返回一个元素,而无需像remove
和swap_remove
那样恢复Vec
的不变性开销。
这似乎是过早的微观优化。
首先,请注意需要销毁向量的元素;您可以通过两种方式实现:
swap_remove
,然后迭代每个元素以销毁它们,
- 迭代每个元素以销毁它们,跳过特定的
index
。
我不确定后者是否比前者更快;如果有什么区别,它看起来更加复杂,有更多分支(我建议使用两个循环),这可能会使预测器失效,并且可能不利于矢量化。
其次,在抱怨恢复Vec
的不变性开销之前,您是否正确地进行了分析?
如果我们查看swap_remove
变体,有3个步骤:
swap_remove
(O(1)),
- 销毁每个剩余元素(O(N)),
- 释放支持内存。
如果元素没有Drop
实现,则步骤2可以优化掉,但否则我认为(2)或(3)哪个占主导成本是不确定的。
简而言之:我担心您正在解决虚假问题,请在尝试优化之前进行分析。
Option<T>
而不是从vec.get(index)
得到的Option<&T>
,还是你忽略了.get
的存在? - loganfsmythOption<T>
。我的意思是,我想要类似于option.take()
的功能,如果这样说有意义的话? - OthersVec
,你可能需要看看是否可以避免一开始就将它们实例化。不做任何事情总是比做任何事情都要快,无论你在做什么时有多么高效。 - Matthieu M.