I'm looking for a method that consumes a Vec
and returns one element, without the overhead of restoring Vec
's invariants the way remove
and swap_remove
do:
fn take<T>(vec: Vec<T>, index: usize) -> Option<T>
However, I can't find such a method. Am I missing something? Is this actually unsafe or impossible?
This is a different question from Built in *safe* way to move out of Vec<T>?
There the goal was a remove
method that didn't panic on out of bounds access and returned a Result
. I'm looking for a method that consumes a Vec
and returns one of the elements. None of the answers to the above question address my question.
You can write your function like this:
fn take<T>(mut vec: Vec<T>, index: usize) -> Option<T> {
if vec.get(index).is_none() {
None
} else {
Some(vec.swap_remove(index))
}
}
The code you see here (get
and swap_remove
) is guaranteed O(1).
However, kind of hidden, vec
is dropped at the end of the function and this drop operation is likely not O(1), but O(n) (where n is vec.len()
). If T
implements Drop
, then drop()
is called for every element still inside the vector, meaning dropping the vector is guaranteed O(n). If T
does not implement Drop
, then the Vec
only needs to deallocate the memory. The time complexity of the dealloc
operation depends on the allocator and is not specified, so we cannot assume it is O(1).
To mention another solution using iterators:
fn take<T>(vec: Vec<T>, index: usize) -> Option<T> {
vec.into_iter().nth(index)
}
While Iterator::nth()
usually is a linear time operation, the iterator over a vector overrides this method to make it a O(1) operation. Of course, if T
implements Drop
, this again is an O(n) function as n elements need to be dropped.