Vec

#115 May 2026

115. Vec::resize_with — Grow a Vec With a Closure, Not a Clone

Vec::resize makes every new slot a clone of the same value. When you need fresh values per slot — counters, allocations, defaults — resize_with calls a closure for each new element instead.

Vec::resize(n, value) is fine when the filler is cheap and identical, but it has two annoyances. It needs T: Clone, and every new slot is the same clone. So this doesn’t work the way you want:

1
2
3
4
5
// One Vec shared across every slot — mutating slot 0 mutates them all.
let mut grid: Vec<Vec<u8>> = Vec::new();
grid.resize(3, Vec::new());
grid[0].push(42);
assert_eq!(grid[1], vec![]); // fine — Vec::new() clones to a new empty Vec

That one happens to be safe because Vec::clone actually allocates. But the moment your T is Rc<RefCell<…>>, every slot points at the same cell. And if T isn’t Clone at all, you can’t call resize in the first place.

resize_with takes a closure and calls it once per new slot:

1
2
3
4
5
6
7
let mut counter = 0;
let mut v = vec![10, 20];
v.resize_with(5, || {
    counter += 1;
    counter
});
assert_eq!(v, vec![10, 20, 1, 2, 3]);

The closure can capture mutable state, so each call is fresh. Generating IDs, pulling from an RNG, allocating independent buffers — all easy:

1
2
3
4
5
6
7
8
9
let mut next_id = 100;
let mut buffers: Vec<(usize, Vec<u8>)> = Vec::new();
buffers.resize_with(3, || {
    let id = next_id;
    next_id += 1;
    (id, Vec::with_capacity(1024))
});
assert_eq!(buffers[0].0, 100);
assert_eq!(buffers[2].0, 102);

For non-Clone types, Default::default is the usual filler:

1
2
3
4
5
6
7
8
9
#[derive(Default, Debug, PartialEq)]
struct Slot {
    open: bool,
    payload: Vec<u8>,
}

let mut slots: Vec<Slot> = Vec::new();
slots.resize_with(2, Default::default);
assert_eq!(slots, vec![Slot::default(), Slot::default()]);

Shrinking still works, and the closure is never called when the new length is smaller:

1
2
3
let mut v = vec![1, 2, 3, 4, 5];
v.resize_with(2, || unreachable!());
assert_eq!(v, vec![1, 2]);

Reach for resize_with whenever the filler isn’t a single static value — and especially when T doesn’t (or shouldn’t) implement Clone.

#111 Apr 2026

111. Vec::insert_mut — Splice In and Edit Without Reindexing

You insert a placeholder, then index back to fix it up. Two lookups, two bounds checks, one wobble. Vec::insert_mut — stable in 1.95 — hands you the &mut T directly.

The classic dance:

1
2
3
4
let mut v = vec![1, 2, 4, 5];
v.insert(2, 0);
v[2] = 3; // recompute the index, second bounds check
assert_eq!(v, [1, 2, 3, 4, 5]);

insert_mut returns the slot:

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

This shines when the value is built in pieces — push a default, then fill it in based on where it landed:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
#[derive(Default, Debug, PartialEq)]
struct Job { id: u32, label: String }

let mut jobs: Vec<Job> = vec![Job { id: 1, label: "build".into() }];
let j = jobs.insert_mut(0, Job::default());
j.id = 0;
j.label = "setup".into();

assert_eq!(jobs[0], Job { id: 0, label: String::from("setup") });
assert_eq!(jobs[1].label, "build");

Rust 1.95 grew the whole _mut family alongside Vec::push_mut: Vec::insert_mut, VecDeque::push_front_mut, VecDeque::push_back_mut, VecDeque::insert_mut, LinkedList::push_front_mut, and LinkedList::push_back_mut. Same idea everywhere — the place-it method now returns a mutable reference to the slot it just placed.

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

let mut q: VecDeque<i32> = VecDeque::from([2, 3]);
let head = q.push_front_mut(0);
*head += 1; // now 1
assert_eq!(q, VecDeque::from([1, 2, 3]));

Quietly useful, no churn — just fewer indices floating around.

#107 Apr 2026

107. Vec::splice — Replace a Range and Keep the Old Values

Need to swap a chunk of a Vec for a different number of items? Most people reach for drain plus extend and a bunch of bookkeeping. Vec::splice does the whole thing in one call — and even hands back what it removed.

The clunky way

You want to replace v[1..4] with two different values. Without splice, you end up juggling indices:

1
2
3
4
5
6
7
8
9
let mut v = vec![1, 2, 3, 4, 5];

// Remove the middle, save the tail, then stitch it back together.
let tail: Vec<_> = v.drain(4..).collect();
v.truncate(1);
v.extend([10, 20]);
v.extend(tail);

assert_eq!(v, [1, 10, 20, 5]);

Three steps, one temporary Vec, and you didn’t even capture what was removed. Easy to off‑by‑one, easy to get wrong.

Enter splice

splice takes a range and an iterator and swaps them in place — the replacement can be any length:

1
2
3
4
5
let mut v = vec![1, 2, 3, 4, 5];

v.splice(1..4, [10, 20]);

assert_eq!(v, [1, 10, 20, 5]);

One call. No tail buffer. Works whether the replacement is shorter, longer, or the same size as the range.

It returns the removed items too

splice is a draining iterator — collect it and you get the elements that were taken out:

1
2
3
4
5
6
let mut v = vec![10, 20, 30, 40, 50];

let removed: Vec<_> = v.splice(1..4, [99]).collect();

assert_eq!(removed, [20, 30, 40]);
assert_eq!(v, [10, 99, 50]);

Perfect for “swap this section, but undo it later” patterns.

Insert without removing

Pass an empty range and splice becomes a multi‑item insert:

1
2
3
4
5
let mut v = vec![1, 5];

v.splice(1..1, [2, 3, 4]);

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

That’s far nicer than calling insert in a loop and watching every push shift the tail again.

When to reach for it

Any time you’d write drain(..) followed by extend(..) or a tower of insert calls, try splice first. One method, one allocation pattern, and the removed items come along for free.

#105 Apr 2026

105. Vec::extend_from_within — Duplicate a Range Without Fighting the Borrow Checker

Trying to copy a slice of a Vec back onto the end of itself? v.extend_from_slice(&v[..k]) won’t compile — &v and &mut v collide. extend_from_within is the one-call answer.

The borrow checker says no

It looks innocent: take the first few bytes of a buffer and append them to the end. The naïve write doesn’t even reach the type checker without complaint:

1
2
3
let mut buf: Vec<u8> = vec![0xCA, 0xFE, 0xBA, 0xBE];
// buf.extend_from_slice(&buf[..2]);
// ^^ error: cannot borrow `buf` as immutable because it is also borrowed as mutable

extend_from_slice needs &mut self, and &buf[..2] is an immutable borrow of the same Vec. Two borrows, one of them mutable, same value — instant rejection.

The usual workarounds bloat the call site. Either make a temporary copy, or reach for unsafe and a raw pointer dance:

1
2
3
4
5
6
let mut buf: Vec<u8> = vec![0xCA, 0xFE, 0xBA, 0xBE];

let head: Vec<u8> = buf[..2].to_vec();   // extra allocation
buf.extend_from_slice(&head);

assert_eq!(buf, [0xCA, 0xFE, 0xBA, 0xBE, 0xCA, 0xFE]);

A whole heap allocation just to copy two bytes inside a vector you already own. There’s a better way.

extend_from_within — one call, no temp

Vec::extend_from_within takes a range into self and appends those elements. No second buffer, no unsafe, no fight with the borrow checker:

1
2
3
4
let mut buf: Vec<u8> = vec![0xCA, 0xFE, 0xBA, 0xBE];
buf.extend_from_within(..2);

assert_eq!(buf, [0xCA, 0xFE, 0xBA, 0xBE, 0xCA, 0xFE]);

It accepts any RangeBounds<usize>..k, i..j, i..=j, .. — so you can grab whatever slice you want, including the whole Vec:

1
2
3
4
let mut v = vec![1, 2, 3];
v.extend_from_within(..);   // double the contents

assert_eq!(v, [1, 2, 3, 1, 2, 3]);

It requires T: Clone, and clones each element exactly once. For Copy types like primitives it lowers to a single memcpy.

A real use: building patterns

It’s especially nice for building repeating or growing patterns where each step depends on the previous one — think DSP buffers, simple test fixtures, or doubling tricks:

1
2
3
4
5
6
7
let mut data = vec![1u32];
for _ in 0..4 {
    data.extend_from_within(..); // double in place
}

assert_eq!(data.len(), 16);
assert!(data.iter().all(|&x| x == 1));

When to reach for it

Any time you’d write v.extend_from_slice(&v[range]) and the borrow checker stops you, swap in v.extend_from_within(range). Stable since Rust 1.53, exists for both Vec<T> and VecDeque<T>, and quietly turns a frustrating compile error into a one-liner.

#104 Apr 2026

104. Vec::swap_remove — O(1) Removal When Order Doesn't Matter

Calling Vec::remove(i) shifts every element after i left by one — that’s O(n) per call. If you don’t care about order, swap_remove does the same job in O(1).

The hidden cost of Vec::remove

remove takes the value out of the vector, but to keep the rest in order it has to shift every following element left by one slot. On a long vector, removing near the front is a giant memcpy:

1
2
3
4
5
let mut v = vec![1, 2, 3, 4, 5];
let removed = v.remove(1);

assert_eq!(removed, 2);
assert_eq!(v, [1, 3, 4, 5]);

Inside a loop — “remove every item that matches X” — that O(n) cost compounds into O(n²). A tight loop that should be linear silently becomes quadratic.

swap_remove: trade order for speed

swap_remove(i) removes the element at index i by swapping it with the last element, then popping the tail. No shifting, no memcpy chain — just one swap and a pop:

1
2
3
4
5
6
let mut v = vec![1, 2, 3, 4, 5];
let removed = v.swap_remove(1);

assert_eq!(removed, 2);
// 5 took 2's spot — order is gone, but the op was O(1).
assert_eq!(v, [1, 5, 3, 4]);

If your Vec is really a set — entities in a game world, pending jobs in a worker pool, items keyed by id elsewhere — order rarely matters. swap_remove is free.

Removing many items in place

The classic mistake: iterate forward calling remove. swap_remove lets you do it without the O(n²) blow-up. Walk by index and don’t bump the cursor when you remove:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
let mut nums = vec![1, 2, 3, 4, 5, 6, 7, 8];

let mut i = 0;
while i < nums.len() {
    if nums[i] % 2 == 0 {
        nums.swap_remove(i);
        // Don't increment — a new element is now at position i.
    } else {
        i += 1;
    }
}

nums.sort(); // canonicalize for the assert
assert_eq!(nums, [1, 3, 5, 7]);

For bulk predicate-based filtering, Vec::retain stays cleaner (and is also O(n)). Reach for swap_remove when you have a specific index you want gone in O(1).

With structs

swap_remove returns the removed value, so you can hand it off to another collection on the way out:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
#[derive(PartialEq, Debug)]
struct Job { id: u32 }

let mut queue = vec![
    Job { id: 1 },
    Job { id: 2 },
    Job { id: 3 },
    Job { id: 4 },
];

let pulled = queue.swap_remove(0);

assert_eq!(pulled, Job { id: 1 });
assert_eq!(queue.len(), 3);

When to reach for it

Use swap_remove whenever you’d write remove(i) and the surrounding code doesn’t depend on element order. Order-preserving removal still needs remove, but most “remove one item from this Vec” code is order-agnostic — and swap_remove turns an O(n) pothole into a one-line O(1) win. Stable since Rust 1.0, one of those quietly-essential APIs that’s easy to forget exists.

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.

#047 Mar 2026

47. Vec::pop_if — Conditionally Pop the Last Element

Need to remove the last element of a Vec only when it meets a condition? Vec::pop_if does exactly that — no index juggling, no separate check-then-pop.

The old way

Before pop_if, you’d write something like this:

1
2
3
4
5
6
let mut stack = vec![1, 2, 3, 4];

if stack.last().is_some_and(|x| *x > 3) {
    let val = stack.pop().unwrap();
    println!("Popped: {val}");
}

Two separate calls, and a subtle TOCTOU gap if you’re not careful — last() checks one thing, then pop() acts on an assumption.

Enter pop_if

Stabilized in Rust 1.86, pop_if combines the check and the removal into one atomic operation:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
let mut stack = vec![1, 2, 3, 4];

// Pop the last element only if it's greater than 3
let popped = stack.pop_if(|x| *x > 3);
assert_eq!(popped, Some(4));
assert_eq!(stack, [1, 2, 3]);

// Now the last element is 3 — doesn't match, so nothing happens
let stayed = stack.pop_if(|x| *x > 3);
assert_eq!(stayed, None);
assert_eq!(stack, [1, 2, 3]);

The closure receives a &mut T reference to the last element. If it returns true, the element is removed and returned as Some(T). If false (or the vec is empty), you get None.

Mutable access inside the predicate

Because the closure gets &mut T, you can even modify the element before deciding whether to pop it:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
let mut tasks = vec![
    String::from("buy milk"),
    String::from("URGENT: deploy fix"),
];

let urgent = tasks.pop_if(|task| {
    if task.starts_with("URGENT:") {
        *task = task.replacen("URGENT: ", "", 1);
        true
    } else {
        false
    }
});

assert_eq!(urgent.as_deref(), Some("deploy fix"));
assert_eq!(tasks, vec!["buy milk"]);

A practical use: draining from the back

pop_if is handy for processing a sorted vec from the tail. Think of a priority queue backed by a sorted vec where you only want to process items above a threshold:

1
2
3
4
5
6
7
8
9
let mut scores = vec![10, 25, 50, 75, 90];

let mut high_scores = Vec::new();
while let Some(score) = scores.pop_if(|s| *s >= 70) {
    high_scores.push(score);
}

assert_eq!(high_scores, vec![90, 75]);
assert_eq!(scores, vec![10, 25, 50]);

Clean, expressive, and no off-by-one errors. Another small addition to Vec that makes everyday Rust just a bit nicer.

43. Vec::extract_if — Remove Elements and Keep Them

Ever needed to split a Vec into two groups — the ones you keep and the ones you remove? retain discards the removed items. Now there’s a better way.

Vec::extract_if (stable since Rust 1.87) removes elements matching a predicate and hands them back as an iterator — in a single pass.

The old way — two passes, logic must stay in sync

1
2
3
4
5
6
7
8
9
let mut numbers = vec![1, 2, 3, 4, 5, 6];

// Collect the evens first…
let evens: Vec<i32> = numbers.iter().filter(|&&x| x % 2 == 0).copied().collect();
// …then remove them (predicate must match exactly)
numbers.retain(|&x| x % 2 != 0);

assert_eq!(numbers, [1, 3, 5]);
assert_eq!(evens,   [2, 4, 6]);

The filter and the retain predicates must be inverses of each other — easy to mistype, and you touch the data twice.

The new way — one pass, one predicate

1
2
3
4
5
6
let mut numbers = vec![1, 2, 3, 4, 5, 6];

let evens: Vec<i32> = numbers.extract_if(.., |&mut x| x % 2 == 0).collect();

assert_eq!(numbers, [1, 3, 5]);
assert_eq!(evens,   [2, 4, 6]);

extract_if walks the Vec, removes every element where the closure returns true, and yields it. The .. is a range — you can narrow it to only consider a slice of the vector.

Real-world example: draining a work queue

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
#[derive(Debug)]
struct Job { id: u32, priority: u8 }

let mut queue = vec![
    Job { id: 1, priority: 3 },
    Job { id: 2, priority: 9 },
    Job { id: 3, priority: 1 },
    Job { id: 4, priority: 8 },
];

// Pull out all high-priority jobs for immediate processing
let urgent: Vec<Job> = queue.extract_if(.., |j| j.priority >= 8).collect();

assert_eq!(urgent.len(), 2);  // jobs 2 and 4
assert_eq!(queue.len(),  2);  // jobs 1 and 3 remain

HashMap and HashSet also gained extract_if in Rust 1.88.

Note: The closure takes &mut T, so you can even mutate elements mid-extraction before deciding whether to remove them.

#008 Feb 2022

8. Drain

Use drain to remove specified range from a vector.

1
2
3
4
5
let mut a = vec![1,2,3,4,5];

let _ = a.drain(0..3);

assert!(a == vec![4,5]);

What is the difference to call into_iter which returns T ?

into_iter takes the collection by value and consumes it.

drain borrows mutable reference, and returns a drain iterator of elements. If such iterator is dropped without exhausting it, all elements are dropped.