#244 Jul 2026

244. clone_from — Reuse the Buffer You Already Have Instead of Reallocating

*dst = src.clone() throws away dst’s heap buffer and allocates a brand-new one every time. dst.clone_from(&src) copies into the storage dst already owns — reusing its capacity instead of freeing and re-grabbing it.

The hidden allocation in assignment

Cloning into an existing variable looks free, but it isn’t:

1
2
3
4
5
6
7
8
9
let mut dst = String::with_capacity(64);
dst.push_str("previous value");

let src = String::from("new value");

// Drops dst's 64-byte buffer, allocates a fresh one for src's length
dst = src.clone();

assert_eq!(dst, "new value");

src.clone() builds a completely new String with its own allocation, then the assignment drops the old dst — buffer and all. In a loop that runs thousands of times, that’s a free-then-allocate churn on every iteration, even when the old buffer was plenty big.

clone_from copies into place

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
let mut dst = String::with_capacity(64);
dst.push_str("previous value");

let src = String::from("new value");

// Overwrites dst's existing buffer; keeps the capacity if it fits
dst.clone_from(&src);

assert_eq!(dst, "new value");
assert!(dst.capacity() >= 64); // same allocation, reused

Clone::clone_from is a provided trait method whose whole job is “make self equal to source, reusing self’s resources where possible.” For String and Vec, that means copying the bytes into the buffer that’s already there and only reallocating if it’s too small. The default impl just does *self = source.clone(), but the collections override it to reuse storage.

Where it pays off: the reused accumulator

The classic win is a buffer you refresh every pass through a loop — pair it with the reuse-one-buffer pattern:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
let inputs = vec![vec![1, 2, 3], vec![4, 5, 6, 7], vec![8]];
let mut scratch: Vec<i32> = Vec::new();

for row in &inputs {
    scratch.clone_from(row); // reuses scratch's capacity each time
    scratch.iter_mut().for_each(|x| *x *= 10);
    // ... use scratch ...
}

assert_eq!(scratch, vec![80]); // last row, scaled

Every clone_from after the first reuses whatever capacity scratch grew to, so the loop stops hammering the allocator. Swap in scratch = row.clone() and you’re back to a fresh allocation on each turn.

It works for any nested owned type too — a Vec<String> clones each element with clone_from, so inner buffers get reused, not rebuilt. Whenever you catch yourself writing dst = src.clone() for a dst you already own, clone_from is the version that doesn’t throw the buffer away.

#243 Jul 2026

243. slice::as_flattened — Treat a Slice of Arrays as One Flat Slice, No Copy

You’ve got a Vec<[f32; 3]> of RGB pixels and an API that wants &[f32]. The manual flatten allocates a whole second buffer. as_flattened hands you the same bytes as a flat &[f32] — zero copies, zero allocation.

The copy you didn’t need

A slice of fixed-size arrays is already contiguous in memory. But reach for a flat view the obvious way and you rebuild it element by element into a fresh Vec:

1
2
3
4
5
6
let pixels: Vec<[f32; 3]> = vec![[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]];

// Rebuilds every value into a new allocation
let flat: Vec<f32> = pixels.iter().flatten().copied().collect();

assert_eq!(flat, vec![1.0, 0.0, 0.0, 0.0, 1.0, 0.0]);

That collect walks all six values and heap-allocates a second buffer — pure waste when the layout you want is already sitting there.

as_flattened is a free reinterpretation

1
2
3
4
5
6
let pixels: Vec<[f32; 3]> = vec![[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]];

let flat: &[f32] = pixels.as_flattened();

assert_eq!(flat, &[1.0, 0.0, 0.0, 0.0, 1.0, 0.0]);
assert_eq!(flat.len(), 6); // outer_len * N

<[[T; N]]>::as_flattened takes &[[T; N]] and returns &[T] covering the exact same memory. No copy, no allocation — just a pointer and a length. The result borrows the original, so it stays as cheap as it looks.

Mutate through the flat view

as_flattened_mut gives you &mut [T], so you can run a flat transform over structured data without unpacking it:

1
2
3
4
5
6
7
let mut rows = [[1, 2, 3], [4, 5, 6]];

for v in rows.as_flattened_mut() {
    *v *= 10;
}

assert_eq!(rows, [[10, 20, 30], [40, 50, 60]]);

Same storage, edited in place — the array grouping is still there when you’re done.

Where it shines: handing structured data to flat APIs

Vertex buffers, audio frames, matrices — anything you model as [T; N] but a lower-level API wants as one long run:

1
2
3
4
5
6
7
8
9
// A 2x3 matrix stored as rows
let matrix = [[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]];

fn dot(a: &[f64], b: &[f64]) -> f64 {
    a.iter().zip(b).map(|(x, y)| x * y).sum()
}

let flat = matrix.as_flattened();
assert_eq!(dot(flat, flat), 91.0); // 1+4+9+16+25+36

You keep the readable [[f64; 3]; 2] shape in your own code and pass a &[f64] across the boundary — no glue buffer in between. Whenever you catch yourself flatten().collect()-ing a slice of arrays just to change its type, as_flattened is the zero-cost version.

#242 Jul 2026

242. slice::binary_search_by_key — Find a Record by One Field, No Hand-Written Comparator

Binary searching a slice of structs by one field? Don’t hand-roll a .cmp() closure and risk flipping the comparison — project the key and let the stdlib do the rest.

You have a slice sorted by some field and want to find an element by that field. The reflex is binary_search_by with a closure that spells out the comparison — and it’s easy to get the argument order backwards, which silently breaks the search:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
#[derive(Debug, PartialEq)]
struct Employee {
    id: u32,
    name: &'static str,
}

let staff = [
    Employee { id: 3,  name: "Ada" },
    Employee { id: 7,  name: "Bo"  },
    Employee { id: 12, name: "Cy"  },
];

// The awkward way — you write (and can mis-order) the comparator
let idx = staff.binary_search_by(|e| e.id.cmp(&7));
assert_eq!(idx, Ok(1));

binary_search_by_key takes the target and a closure that projects the key. No .cmp(), nothing to get backwards:

1
2
3
let idx = staff.binary_search_by_key(&7, |e| e.id);
assert_eq!(idx, Ok(1));
assert_eq!(staff[idx.unwrap()].name, "Bo");

On a miss you get Err(i) — the index where the element would go to keep the slice sorted, so you can insert without a second search:

1
2
3
4
match staff.binary_search_by_key(&10, |e| e.id) {
    Ok(i)  => println!("found at {i}"),
    Err(i) => println!("would insert at {i}"), // Err(2)
}

One rule: the slice must already be sorted by the same key you project, otherwise the result is unspecified. When that holds, it’s O(log n) instead of the O(n) scan you’d write by hand.

#241 Jul 2026

241. slice::split_first — Peel the Head Off a Slice, Keep the Tail, No Indexing

slice[0] panics on an empty slice, and &slice[1..] is a second chance to get the bounds wrong. split_first hands you the head and the tail together — or None if there’s nothing there — so the empty case is a pattern, not a panic.

The manual head-and-tail

Reach for the first element and the rest, and you write two indexing operations that both assume the slice is non-empty:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
fn describe(items: &[&str]) -> String {
    if items.is_empty() {
        return "nothing".to_string();
    }
    let first = items[0];      // panics if you forget the guard above
    let rest = &items[1..];    // and so does this
    format!("{first} plus {} more", rest.len())
}

assert_eq!(describe(&["a", "b", "c"]), "a plus 2 more");

The bounds check is real, but it’s on you to remember the is_empty guard. Drop it and an empty slice panics at runtime.

split_first gives you both, safely

1
2
3
4
5
6
7
8
9
fn describe(items: &[&str]) -> String {
    match items.split_first() {
        Some((first, rest)) => format!("{first} plus {} more", rest.len()),
        None => "nothing".to_string(),
    }
}

assert_eq!(describe(&["a", "b", "c"]), "a plus 2 more");
assert_eq!(describe(&[]), "nothing"); // no panic — the None arm handles it

split_first returns Option<(&T, &[T])>: the first element and a slice of everything after it, or None when the slice is empty. The empty case can’t be forgotten — it’s a variant you have to match.

split_last peels from the other end

1
2
3
4
5
6
let path = ["usr", "local", "bin"];

if let Some((last, parents)) = path.split_last() {
    assert_eq!(*last, "bin");
    assert_eq!(parents, &["usr", "local"]);
}

Same shape, mirrored: the last element plus everything before it.

Where it shines: recursion without index math

Because the tail is just another slice, split_first makes structural recursion clean — the base case is None, and there’s no i + 1 to fumble:

1
2
3
4
5
6
7
8
9
fn sum(slice: &[i32]) -> i32 {
    match slice.split_first() {
        Some((head, tail)) => head + sum(tail),
        None => 0,
    }
}

assert_eq!(sum(&[1, 2, 3, 4]), 10);
assert_eq!(sum(&[]), 0);

Need to mutate as you walk? split_first_mut and split_last_mut return (&mut T, &mut [T]), so you can edit the head and recurse into the tail without a borrow fight. Whenever you catch yourself pairing slice[0] with &slice[1..], this is the method that folds both — and the empty check — into one.

#240 Jul 2026

240. to_le_bytes / from_le_bytes — Serialize Integers Without unsafe or Bit-Shifting

Packing a u32 into four bytes by hand means a stack of >> and as u8 casts — and one wrong shift silently corrupts your data. Every integer type already knows how to lay itself out, in the exact endianness you ask for.

The hand-rolled shift-and-mask

Serializing an integer to bytes the manual way is easy to get subtly wrong:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
let n: u32 = 300;

// big-endian by hand: shift, cast, repeat
let bytes = [
    (n >> 24) as u8,
    (n >> 16) as u8,
    (n >> 8) as u8,
    n as u8,
];
assert_eq!(bytes, [0, 0, 1, 44]);

It works, but the shift amounts are magic numbers, the byte order is implicit, and reversing it (parsing bytes back into a u32) means another shift ladder in the opposite direction.

to_*_bytes hands you the array

Every integer type has to_be_bytes, to_le_bytes, and to_ne_bytes, each returning a fixed-size [u8; N]:

1
2
3
4
let n: u32 = 0x12345678;

assert_eq!(n.to_be_bytes(), [0x12, 0x34, 0x56, 0x78]); // big-endian
assert_eq!(n.to_le_bytes(), [0x78, 0x56, 0x34, 0x12]); // little-endian

The endianness is spelled out in the method name, the array length is checked at compile time ([u8; 4] for a u32), and there’s no cast to fumble.

from_*_bytes parses it back

The inverse takes the same fixed-size array and rebuilds the integer:

1
2
3
4
let n: u32 = 300;
let wire = n.to_be_bytes();

assert_eq!(u32::from_be_bytes(wire), 300); // exact round-trip

Reading an integer out of a buffer

The array size is part of the type, so slice a &[u8] and try_into an array before parsing — the length check happens for you:

1
2
3
4
let buf = [0x00, 0x00, 0x01, 0x2c, 0xff]; // 4-byte int + trailing byte

let n = u32::from_be_bytes(buf[..4].try_into().unwrap());
assert_eq!(n, 300);

If the slice is the wrong length, try_into returns an Err instead of reading past the end — no unsafe, no out-of-bounds read.

Use to_be_bytes / from_be_bytes for network and file formats (big-endian is the usual “wire” order), _le_ when a spec demands little-endian, and reach for _ne_ (native) only for in-memory blobs that never leave the machine. Floats have the same methods, and to_bits / from_bits if you want the raw u32/u64 first.

#239 Jul 2026

239. Vec::drain — Remove a Range and Keep What You Pulled Out

truncate throws elements away. split_off allocates a second Vec. When you want to remove a range from a Vec and actually use those elements — and keep the rest — drain hands them to you as an iterator and shifts everything else down for you.

The manual remove-and-collect

Say you want to pull a batch out of the front of a queue and process it:

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

// take the first three, keep the rest
let mut batch = Vec::new();
for _ in 0..3 {
    batch.push(queue.remove(0)); // each remove is O(n): shifts everything left
}
assert_eq!(batch, vec![1, 2, 3]);
assert_eq!(queue, vec![4, 5]);

Every remove(0) shifts the whole tail down one slot — quadratic for a batch, and the intent is buried in a loop.

drain does it in one pass

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

let batch: Vec<_> = queue.drain(0..3).collect();

assert_eq!(batch, vec![1, 2, 3]);
assert_eq!(queue, vec![4, 5]);

drain(range) removes that range, yields the removed elements in order, and shifts the remaining tail down once. You own the drained values — collect them, iterate them, or pipe them straight into another call.

Drain the whole thing to reuse the allocation

drain(..) empties the Vec but keeps its capacity, so the buffer is ready to refill without reallocating:

1
2
3
4
5
6
7
8
let mut buf = vec![10, 20, 30];
let cap = buf.capacity();

let sum: i32 = buf.drain(..).sum(); // consume every element by value
assert_eq!(sum, 60);

assert!(buf.is_empty());
assert_eq!(buf.capacity(), cap); // allocation retained — refill it next loop

That’s the move-out-and-reuse trick: unlike into_iter(), which consumes the Vec, drain(..) leaves you an empty-but-allocated Vec to keep using.

The removal happens even if you don’t consume it

Drain is a draining iterator: dropping it removes the range regardless of how many items you pulled. So queue.drain(1..4); on its own still deletes that range — you don’t have to .collect() to make it take effect.

1
2
3
let mut v = vec!['a', 'b', 'c', 'd', 'e'];
v.drain(1..4); // dropped immediately; range is gone
assert_eq!(v, vec!['a', 'e']);

Reach for drain over retain when you’re removing a contiguous range by position (not a predicate), and over split_off when you don’t want a second allocation. If you need conditional removal from anywhere, that’s extract_if; if you just want the values gone, truncate is cheaper.

#238 Jul 2026

238. slice::chunks_exact_mut — Edit a Slice in Fixed-Size Blocks Without Index Math

Processing a buffer N elements at a time usually means a while i + N <= len loop and a pile of buf[i..i+N] slicing. chunks_exact_mut hands you each fixed-size block as a &mut [T] — no index bookkeeping, no off-by-one.

The manual-window loop

1
2
3
4
5
6
7
let mut buf = [10, 20, 30, 40, 50, 60];
let mut i = 0;
while i + 2 <= buf.len() {
    buf[i..i + 2].reverse(); // swap each adjacent pair
    i += 2;
}
assert_eq!(buf, [20, 10, 40, 30, 60, 50]);

It works, but every one of i + 2, <= len, and i += 2 is a place to get the bounds wrong.

chunks_exact_mut yields the blocks for you

1
2
3
4
5
let mut buf = [10, 20, 30, 40, 50, 60];
for pair in buf.chunks_exact_mut(2) {
    pair.reverse();
}
assert_eq!(buf, [20, 10, 40, 30, 60, 50]);

Each pair is a &mut [T; 2]-shaped slice you can mutate in place. The iterator stops once fewer than 2 elements remain, so you never index past the end.

The “exact” part: a leftover tail is skipped, not sliced

Unlike chunks_mut, the last partial block is not yielded — that guarantee is exactly why the block size is reliable:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
let mut buf = [1, 2, 3, 4, 5]; // 5 isn't a multiple of 2
let mut it = buf.chunks_exact_mut(2);
for pair in it.by_ref() {
    pair.swap(0, 1);
}
// grab the odd element that didn't fill a block
let tail = it.into_remainder();
assert_eq!(tail, &mut [5][..]);

assert_eq!(buf, [2, 1, 4, 3, 5]); // last 5 left untouched

Reach for the remainder through by_ref() + into_remainder(): iterate the full blocks, then claim whatever fell short. If you drop the loop’s by_ref(), the iterator is moved and into_remainder is unavailable.

Why not just chunks_mut?

chunks_mut(n) also walks a slice in steps of n, but its final chunk can be shorter than n, so any code assuming a fixed width needs a length check every iteration. chunks_exact_mut trades that partial tail for a compile-time-friendly promise that every yielded block is exactly n long — which also lets the optimizer generate tighter code. There’s a read-only chunks_exact for &[T], and as_chunks_mut if you want real &mut [T; N] arrays instead of slices.

#237 Jul 2026

237. Iterator::eq — Compare Two Sequences Without Collecting Them First

Comparing a Vec to an array, or a filtered iterator to an expected result? You don’t need to collect() both sides into the same type first.

The usual reflex is to force both sequences into matching containers so == works:

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

// Allocates a throwaway Vec just to compare.
assert_eq!(v, a.to_vec());

Iterator::eq compares element-by-element straight off the iterators. No allocation, and the two sides don’t even have to be the same container type:

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

assert!(v.iter().eq(a.iter()));

It short-circuits, so a length or value mismatch stops early instead of walking both sequences to the end:

1
assert!([1, 2, 3].iter().ne([1, 2].iter()));

The real payoff is comparing a lazy chain to an expected sequence without materializing it:

1
2
let evens = (1..=6).filter(|n| n % 2 == 0);
assert!(evens.eq([2, 4, 6]));

And the same family does lexicographic ordering, again with no intermediate Vec:

1
2
3
4
use std::cmp::Ordering;

assert_eq!([1, 2, 3].iter().cmp([1, 2, 4].iter()), Ordering::Less);
assert!([1, 2].iter().lt([1, 3].iter()));

So the toolkit is eq, ne, cmp, lt, le, gt, ge — full equality and ordering over any two iterators, no collecting required.

236. Result::flatten — Collapse a Result<Result<T, E>, E> in One Call

Ended up with a Result<Result<T, E>, E> and reached for a nested match to peel it? When both layers share the same error type, Result::flatten (stable since 1.89) does it in one call.

How you get a doubly-wrapped Result

It usually sneaks in when you map a fallible operation over something that’s already a Result:

1
2
3
4
5
6
7
8
fn first_word(line: Result<&str, String>) -> Result<Result<u32, String>, String> {
    line.map(|s| {
        s.split_whitespace()
            .next()
            .ok_or_else(|| "empty line".to_string())
            .and_then(|w| w.parse::<u32>().map_err(|e| e.to_string()))
    })
}

The outer Result is “did we have a line?”, the inner one is “did it parse?”. Same String error on both — but the type is now Result<Result<u32, String>, String>, which no caller wants to touch.

The manual peel

1
2
3
4
5
6
7
8
let nested: Result<Result<u32, String>, String> = Ok(Ok(42));

let flat: Result<u32, String> = match nested {
    Ok(inner) => inner,   // inner is itself a Result
    Err(e) => Err(e),
};

assert_eq!(flat, Ok(42));

Correct, but it’s boilerplate that hides the intent.

flatten does exactly this

1
2
3
4
5
6
7
let ok:    Result<Result<u32, String>, String> = Ok(Ok(42));
let inner: Result<Result<u32, String>, String> = Ok(Err("bad".into()));
let outer: Result<Result<u32, String>, String> = Err("io".into());

assert_eq!(ok.flatten(),    Ok(42));
assert_eq!(inner.flatten(), Err("bad".to_string()));
assert_eq!(outer.flatten(), Err("io".to_string()));

Ok(Ok(x)) becomes Ok(x); either Err — inner or outer — passes straight through. Option has the same method, Option::flatten, for Option<Option<T>>.

The catch: error types must match

flatten is Result<Result<T, E>, E>Result<T, E> — one E. If the two layers carry different error types, flatten can’t merge them. Reach for and_then instead, which lets ?-style conversion do the work:

1
2
3
4
5
let nested: Result<Result<u32, String>, String> = Ok(Ok(7));

// same as .flatten() here, but and_then can also adapt the inner error
let flat = nested.and_then(|inner| inner);
assert_eq!(flat, Ok(7));

When the errors already line up, flatten is the clearest way to say “unwrap one layer of nesting.”

#235 Jul 2026

235. Iterator::rposition — Find the Last Match Without Reversing-and-Subtracting

Need the index of the last element that matches? The reflex is iter().rev().position(...) then len - 1 - i — and that arithmetic is a classic off-by-one. rposition searches from the back and hands you the real forward index.

The reversed-index trap

1
2
3
4
5
6
7
let bytes = [b'a', b'/', b'b', b'/', b'c'];

// "index of the last slash" — the fragile way
let from_end = bytes.iter().rev().position(|&b| b == b'/').unwrap();
let idx = bytes.len() - 1 - from_end;

assert_eq!(idx, 3);

position on a reversed iterator counts from the end, so you have to flip it back with len - 1 - i. Get the - 1 wrong and you’re off by one.

rposition does the flip for you

1
2
3
4
5
let bytes = [b'a', b'/', b'b', b'/', b'c'];

let idx = bytes.iter().rposition(|&b| b == b'/');

assert_eq!(idx, Some(3)); // real index, counted from the front

rposition walks from the back but returns the index in the original, forward order — no arithmetic, and None when nothing matches instead of a panic on the empty case.

It short-circuits from the right

Just as position stops at the first match from the front, rposition stops at the first match from the back — so it only scans the tail it needs:

1
2
3
4
5
let nums = [1, 2, 3, 4, 5, 6];

// last even number
let idx = nums.iter().rposition(|&n| n % 2 == 0);
assert_eq!(idx, Some(5)); // stopped immediately at 6

The requirement

rposition needs a DoubleEndedIterator (so it can walk backwards) that is also an ExactSizeIterator (so it knows the length to report the front index). Slices, Vec, and arrays give you both. A lazy adapter like filter isn’t ExactSizeIterator, so index a slice or collect first.

For string byte or substring searches, str::rfind is the more direct tool — but for an arbitrary predicate over any exact-size sequence, rposition is the one to reach for.