Skip to content

Vec::extend_from_within

Vec methods · Collections

Level: reference · for working programmers

One line: Clone a range of this vector onto its own end.

pub fn extend_from_within<R>(&mut self, src: R)
where
    R: RangeBounds<usize>,

Stable since 1.53.0.

The one that needs no second vector. The obvious hand-written version does not compile:

fn main() {
    let mut v = vec![0, 1, 2, 3];
    // v.extend_from_slice(&v[1..3]);   // error[E0502]: cannot borrow `v` as mutable
    //                                  // because it is also borrowed as immutable
    v.extend_from_within(1..3);
    println!("{v:?}");                  // [0, 1, 2, 3, 1, 2]
}

extend_from_slice would need &self and &mut self at the same time. extend_from_within takes only &mut self and reads the range internally, which is why the method exists at all rather than being a two-liner.

Any RangeBounds<usize> shape works — .., 2.., ..=1, 1..3. The full range doubles the vector, and repeated doubling is the cheap way to build a long repeating pattern.

T: Clone, and the clone really happens: the appended elements are independent, not aliases.

Panics if the range is out of bounds or inverted.

Example

vec_extend_from_within.rs in full — pasted here by tools/run_examples.py from the file CI compiles and runs.

fn main() {
    // Copies a range of this vector onto its own end. No second vector,
    // no temporary, no borrow conflict.
    let mut v = vec![0, 1, 2, 3, 4];
    v.extend_from_within(1..3);
    println!("{v:?}");

    // The obvious hand-written version does not compile: extend_from_slice
    // would need &self and &mut self at the same time.
    // v.extend_from_slice(&v[1..3]);   // error[E0502]

    // Full range doubles the vector.
    let mut v = vec!["a", "b", "c"];
    v.extend_from_within(..);
    println!("{v:?}");

    // Any RangeBounds shape works.
    let mut v = vec![1, 2, 3, 4];
    v.extend_from_within(2..);
    println!("2.. {v:?}");
    let mut v = vec![1, 2, 3, 4];
    v.extend_from_within(..=1);
    println!("..=1 {v:?}");

    // T: Clone, and the clone really happens — this is a copy, not an alias.
    let mut v = vec![String::from("x")];
    v.extend_from_within(..);
    v[0].push('!');
    println!("{v:?}");

    // Repeated doubling is how you build a long repeating pattern cheaply.
    let mut pattern = vec![1u8, 2, 3];
    while pattern.len() < 12 { pattern.extend_from_within(..); }
    println!("{pattern:?} len {}", pattern.len());

    // An out-of-range end panics, like any slice index.
    let hook = std::panic::take_hook();
    std::panic::set_hook(Box::new(|_| {}));
    let caught = std::panic::catch_unwind(|| {
        let mut v = vec![1, 2];
        v.extend_from_within(0..9);
    });
    std::panic::set_hook(hook);
    println!("out-of-range range panicked: {}", caught.is_err());
}

Verified output of vec_extend_from_within.rs — regenerated by tools/run_examples.py, never hand-typed.

[0, 1, 2, 3, 4, 1, 2]
["a", "b", "c", "a", "b", "c"]
2.. [1, 2, 3, 4, 3, 4]
..=1 [1, 2, 3, 4, 1, 2]
["x!", "x"]
[1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3] len 12
out-of-range range panicked: true

See also

Vec::extend_from_within in the standard library ↗