#244 Jul 6, 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.

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