What pop does
The pop method removes the last element of a Vec and shortens it by one. It is the counterpart of push: one adds at the end, the other takes from the end. Both are cheap, because no other element has to move.
let mut three_arr = vec![1, 4, 6];
three_arr.pop();
println!("{:?}", three_arr);
three_arr.pop();
println!("{:?}", three_arr);
[1, 4]
[1]
Each call removes whatever is last at that moment, so calling it twice in a row removes the last two elements, in order from the end.
The return value
Unlike methods that only change the vector, pop also gives you the element it removed. Because the vector might be empty, the result is an Option: Some(value) when there was a last element, and None when there wasn't.
let mut ages = vec![14, 32, 50, 21];
let popped = ages.pop();
println!("{:?} {:?}", popped, ages);
let mut empty: Vec<i32> = Vec::new();
println!("{:?}", empty.pop());
Some(21) [14, 32, 50]
None
Popping an empty vector is not an error. It does nothing and returns None. That makes pop safer than indexing the last element by hand, since v[v.len() - 1] would fail on an empty vector.
Using or ignoring the result
When you only want the element gone, as in this lesson, just call pop() as a statement and ignore the result. When you want the value, you have several choices:
if let Some(x) = v.pop()runs a block only when there was an element.v.pop().unwrap()gives the plain value but panics on an empty vector, so use it only when you know the vector isn't empty.v.pop().unwrap_or(0)supplies a fallback for the empty case.
Popping in a loop
Because pop returns None at the end, it combines well with while let to empty a vector from the back, which is how a stack is usually processed:
let mut st = vec![1, 2, 3];
while let Some(top) = st.pop() {
print!("{} ", top);
}
println!();
3 2 1
The loop stops by itself when the vector is empty. Last in, first out is exactly this behaviour.
Gotchas in Rust
The vector must be mut
Removing an element changes the vector, so the binding needs let mut. Without it, the compiler reports that it cannot borrow the vector as mutable.
Only the last element
pop takes no argument and never removes from the front or the middle. For other positions, other methods exist, such as remove(index), which shifts everything after the index.
Indexes shift at the end
After a pop, the length is one smaller, so the old last index no longer exists. If a vector had four elements and you pop once, reading index 3 now panics because only indexes 0 to 2 remain. Recompute positions from len() after changing the vector.
The lesson's exercise
The starter code gives two mutable vectors, fruits with three strings and ages with four numbers. The exercise has two steps.
- Remove the last fruit. One call to
fruits.pop()removes"grapefruit". The result is ignored, because the lesson only needs the vector to change. - Remove the last two ages. Call
ages.pop()twice, on two lines. The first call removes 21 and the second removes 50.
let mut fruits = vec!["mango", "kiwi", "grapefruit"];
let mut ages = vec![14, 32, 50, 21];
fruits.pop();
ages.pop();
ages.pop();
Afterwards fruits is ["mango", "kiwi"] and ages is [14, 32].
Key takeaways
v.pop()removes the last element and returns it asSome(value), orNoneif the vector was empty.- The vector must be declared with
let mut. - Ignoring the result is fine when you only want the element removed.
while let Some(x) = v.pop()processes a vector from the back until it is empty.
