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.