29

I've been looking over the documentation, and so far I haven't seen a built in function to safely move an item out of a Vec.

Vec::get exists, but that just borrows. Vec::remove exists, and while that does move out of the vector, it also panics if the index is out of range. So, I have two questions:

  1. What is the intended/good way to move an item from a vector?
  2. remove(&mut self, index: usize) -> T panics if out of range. What might be the reason for panicking? Why isn't it implemented like remove(&mut self, index: usize) -> Option<T>?
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
FizzBazer
  • 337
  • 1
  • 3
  • 10
  • 5
    In my experience it's pretty rare to have indices into a vector where you don't know if they're valid. Panicking fits that common case, where an invalid index represents a bug. For the uncommon case you can simply validate the index before using it. – CodesInChaos May 29 '16 at 12:21

3 Answers3

20

If you say safe in a Rust context, we think of memory safety. .remove(i) is certainly safe in regular Rust terms, just to clarify. Calling panic!() is safe.

The error behavior of .remove(i) and .swap_remove(i) is the same as for indexing a vector with v[i] syntax: If i is out of bounds, it's a programmer bug and the library functions panic. This is also called the contract violation clause in the error handling guidelines.

So the thought behind the library is that you only use v[i] or v.remove(i) if you know that i is in bounds, and you can indeed check that it is using i < v.len() or v.get(i) if you want.

There's another function that allows you to move an element out of a vector without possibility to panic, and that is v.pop() which removes the last item in the vector, returning Option<T> for a Vec<T>.

bluss
  • 12,472
  • 1
  • 49
  • 48
  • 1
    That's a good point about safety. Apologies for using the term incorrectly. With that said, is there a meaningful difference between `v.get` and `v.remove` regarding their behaviors? – FizzBazer May 27 '16 at 17:20
  • 2
    `get` exists so that there is an option-returning way to index. (The main indexing facility is `v[i]`). There's no option-returning version of `remove`. – bluss May 27 '16 at 17:22
8

You can use Vec::into_iter() to get an iterator that yields moved objects, and then use iterator APIs to select the item you want.

To move the first item out of a Vec (and throw away all others):

my_vec.into_iter().next()
    .expect("Expecting at least 1 item in vec")
sffc
  • 6,186
  • 3
  • 44
  • 68
5

There's also vec::drain which will give you an iterator over a range of values that were removed. Now that I look at it though, this method would also panic on out-of-bounds access...

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
GhotiPhud
  • 916
  • 1
  • 13
  • 21