#088 Apr 18, 2026

88. Vec::push_mut — Push and Modify in One Step

Tired of pushing a default into a Vec and then grabbing a mutable reference to fill it in? Rust 1.95 stabilises push_mut, which returns &mut T to the element it just inserted.

The old dance

A common pattern is to push a placeholder value and then immediately mutate it. Before push_mut, you had to do an awkward two-step:

1
2
3
4
5
6
7
8
9
let mut names = Vec::new();

// Push, then index back in to mutate
names.push(String::new());
let last = names.last_mut().unwrap();
last.push_str("hello");
last.push_str(", world");

assert_eq!(names[0], "hello, world");

That last_mut().unwrap() is boilerplate — you know the element is there because you just pushed it. Worse, in more complex code the compiler can’t always prove the reference is safe, forcing you into index gymnastics.

Enter push_mut

push_mut pushes the value and hands you back a mutable reference in one shot:

1
2
3
4
5
6
7
let mut scores = Vec::new();

let entry = scores.push_mut(0);
*entry += 10;
*entry += 25;

assert_eq!(scores[0], 35);

No unwraps, no indexing, no second lookup. The borrow checker is happy because there’s a clear chain of ownership.

Building structs in-place

This really shines when you’re constructing complex values piece by piece:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
#[derive(Debug, Default)]
struct Player {
    name: String,
    score: u32,
    active: bool,
}

let mut roster = Vec::new();

let p = roster.push_mut(Player::default());
p.name = String::from("Ferris");
p.score = 100;
p.active = true;

assert_eq!(roster[0].name, "Ferris");
assert_eq!(roster[0].score, 100);
assert!(roster[0].active);

Instead of building the struct fully before pushing, you push a default and fill it in. This can be handy when the final field values depend on context you only have after insertion.

Also works for insert_mut

Need to insert at a specific index? insert_mut follows the same pattern:

1
2
3
4
5
let mut v = vec![1, 3, 4];
let inserted = v.insert_mut(1, 2);
*inserted *= 10;

assert_eq!(v, [1, 20, 3, 4]);

Both methods are also available on VecDeque (push_front_mut, push_back_mut, insert_mut) and LinkedList (push_front_mut, push_back_mut).

When to reach for it

Use push_mut whenever you’d otherwise write push followed by last_mut().unwrap(). It’s one less unwrap, one fewer line, and clearer intent: push this, then let me tweak it.

Stabilised in Rust 1.95 (April 2026) — update your toolchain and give it a spin.

← Previous 87. Atomic update — Kill the Compare-and-Swap Loop