我想要的是这样的方法:
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}}做。
答案 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}}做。
这对我来说是过早的微观优化。
首先,请注意有必要销毁向量的元素;你可以通过两种方式实现这一目标:
swap_remove
,然后迭代每个元素以销毁它们,swap_remove
。我不清楚后者会比前者更快;如果它看起来更复杂,有更多的分支(我建议两个循环),这可能会抛弃预测器,可能不太适合矢量化。
其次,在抱怨恢复index
的不变量的开销之前,你有没有正确地描述解决方案?
如果我们查看Vec
变体,则有3个步骤:
swap_remove
(O(1)),如果元素没有swap_remove
实现,则可以优化步骤2,但否则我将是抛出是否(2)或(3)支配成本。
TL; DR :在尝试优化之前,我担心你会遇到幽灵问题个人资料。