diff options
| author | Matthias Krüger <476013+matthiaskrgr@users.noreply.github.com> | 2025-09-25 18:15:09 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-09-25 18:15:09 +0200 |
| commit | fea9196e5271a61dc526246a6ccdc2db0f998603 (patch) | |
| tree | 49118852543474c42710fb3a27c1483a280473d8 | |
| parent | 958d1438b6916ade1b89d8527c898254159685c3 (diff) | |
| parent | 56734495e2fd485a7be1ba77da1bf18a0eca4636 (diff) | |
| download | rust-fea9196e5271a61dc526246a6ccdc2db0f998603.tar.gz rust-fea9196e5271a61dc526246a6ccdc2db0f998603.zip | |
Rollup merge of #146293 - BenjaminBrienen:try_remove, r=joboet
feat: non-panicking `Vec::try_remove`
`if index < my_vector.len() { Some(my_vector.remove(index)) } else { None }` is annoying to write and non-panicking functions are broadly useful.
APC: https://github.com/rust-lang/libs-team/issues/649
Tracking issue: https://github.com/rust-lang/rust/issues/146954
| -rw-r--r-- | library/alloc/src/vec/mod.rs | 32 | ||||
| -rw-r--r-- | library/alloctests/tests/lib.rs | 1 | ||||
| -rw-r--r-- | library/alloctests/tests/vec.rs | 15 |
3 files changed, 46 insertions, 2 deletions
diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index ebdb86f98a8..694b7b2df08 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -2173,9 +2173,37 @@ impl<T, A: Allocator> Vec<T, A> { panic!("removal index (is {index}) should be < len (is {len})"); } + match self.try_remove(index) { + Some(elem) => elem, + None => assert_failed(index, self.len()), + } + } + + /// Remove and return the element at position `index` within the vector, + /// shifting all elements after it to the left, or [`None`] if it does not + /// exist. + /// + /// Note: Because this shifts over the remaining elements, it has a + /// worst-case performance of *O*(*n*). If you'd like to remove + /// elements from the beginning of the `Vec`, consider using + /// [`VecDeque::pop_front`] instead. + /// + /// [`VecDeque::pop_front`]: crate::collections::VecDeque::pop_front + /// + /// # Examples + /// + /// ``` + /// #![feature(vec_try_remove)] + /// let mut v = vec![1, 2, 3]; + /// assert_eq!(v.try_remove(0), Some(1)); + /// assert_eq!(v.try_remove(2), None); + /// ``` + #[unstable(feature = "vec_try_remove", issue = "146954")] + #[rustc_confusables("delete", "take", "remove")] + pub fn try_remove(&mut self, index: usize) -> Option<T> { let len = self.len(); if index >= len { - assert_failed(index, len); + return None; } unsafe { // infallible @@ -2191,7 +2219,7 @@ impl<T, A: Allocator> Vec<T, A> { ptr::copy(ptr.add(1), ptr, len - index - 1); } self.set_len(len - 1); - ret + Some(ret) } } diff --git a/library/alloctests/tests/lib.rs b/library/alloctests/tests/lib.rs index 8c3ce156f3c..cba9883e148 100644 --- a/library/alloctests/tests/lib.rs +++ b/library/alloctests/tests/lib.rs @@ -41,6 +41,7 @@ #![feature(unique_rc_arc)] #![feature(macro_metavar_expr_concat)] #![feature(vec_peek_mut)] +#![feature(vec_try_remove)] #![allow(internal_features)] #![deny(fuzzy_provenance_casts)] #![deny(unsafe_op_in_unsafe_fn)] diff --git a/library/alloctests/tests/vec.rs b/library/alloctests/tests/vec.rs index 33a34daccbf..ea334ab0f14 100644 --- a/library/alloctests/tests/vec.rs +++ b/library/alloctests/tests/vec.rs @@ -631,6 +631,21 @@ fn test_swap_remove_empty() { } #[test] +fn test_try_remove() { + let mut vec = vec![1, 2, 3]; + // We are attempting to remove vec[0] which contains 1 + assert_eq!(vec.try_remove(0), Some(1)); + // Now `vec` looks like: [2, 3] + // We will now try to remove vec[2] which does not exist + // This should return `None` + assert_eq!(vec.try_remove(2), None); + + // We will try the same thing with an empty vector + let mut v: Vec<u8> = vec![]; + assert!(v.try_remove(0).is_none()); +} + +#[test] fn test_move_items() { let vec = vec![1, 2, 3]; let mut vec2 = vec![]; |
