#228 Jun 28, 2026

228. Vec::push_mut — Push and Get a &mut Back, Skip the last_mut().unwrap()

Pushed an element and immediately needed to tweak it? The old way was push then last_mut().unwrap(). Rust 1.95 added push_mut, which hands you the &mut right back.

The push-then-refetch dance

You add an element to a Vec, then need a mutable handle to it — to set a field, run a builder step, whatever. push returns (), so you go fishing for what you just put in:

1
2
3
4
5
6
7
struct Span { start: usize, end: usize }

let mut spans = Vec::new();
spans.push(Span { start: 0, end: 0 });
let last = spans.last_mut().unwrap(); // re-fetch what we just pushed
last.end = 10;
assert_eq!(spans[0].end, 10);

That last_mut().unwrap() is pure ceremony. You know it’s there — you pushed it one line ago — but the type system makes you unwrap an Option anyway.

push_mut returns the reference directly

Stabilized in Rust 1.95, Vec::push_mut appends the value and returns a &mut T to it in one step:

1
2
3
4
5
6
struct Span { start: usize, end: usize }

let mut spans = Vec::new();
let last = spans.push_mut(Span { start: 0, end: 0 });
last.end = 10;
assert_eq!(spans[0].end, 10);

No Option, no unwrap, no second lookup. The borrow checker is happy because the returned reference is tied to the Vec.

Where it shines: build-then-mutate loops

Parsing or accumulating state where each new entry gets refined before you move on reads much cleaner:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
#[derive(Debug, PartialEq)]
struct Token { text: String, len: usize }

let mut tokens = Vec::new();
for word in "fn main".split_whitespace() {
    let tok = tokens.push_mut(Token { text: word.to_string(), len: 0 });
    tok.len = tok.text.len(); // fill in a derived field in place
}

assert_eq!(tokens[0], Token { text: "fn".into(), len: 2 });
assert_eq!(tokens[1], Token { text: "main".into(), len: 4 });

Not just Vec

The same _mut family landed across the collections: Vec::insert_mut, VecDeque::push_front_mut / push_back_mut / insert_mut, and LinkedList::push_front_mut / push_back_mut all return a &mut to the freshly inserted element:

1
2
3
4
5
6
use std::collections::VecDeque;

let mut q = VecDeque::new();
let front = q.push_front_mut(1);
*front += 41;
assert_eq!(q[0], 42);

Whenever you push and immediately need to touch what you pushed, reach for push_mut — the reference is already in your hand.

← Previous 227. trim_matches — Strip the Same Char Off Both Ends, However Many There Are Next → 229. char::to_digit — Turn a Digit Character Into Its Value, Not Its Byte