Skip to content

Instantly share code, notes, and snippets.

@danielhenrymantilla
Last active January 9, 2022 13:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save danielhenrymantilla/989940e2c37bfc9f892e3fd1c77de860 to your computer and use it in GitHub Desktop.
Save danielhenrymantilla/989940e2c37bfc9f892e3fd1c77de860 to your computer and use it in GitHub Desktop.
Vec off arrays (or slices)

Question

how can I convert an array to a vec without cloning the values

Technically-correct answer

Make a Vec of references:

array.iter_mut().collect::<Vec<_>>();

no cloning involved, and you have a Vec.

In practice, however, it's gonna be lifetime-bound (Vec<&mut T> or Vec<&T> if using .iter()). Hence the following more useful answer, but it may involve cloning or other stuff.

Array [T; N] (or slice [T]) to Vec<T> conversions

In the following snippets, consider that array is an expression of type [T; N] (an array), or a [T] (a slice), but then behind some form of indirection (slices need pointer indirection): &[T], &mut [T] or Box<[T]> (or &move [T]).

To avoid extra lifetime/borrowing restrictions, you'll need to have owned values in the resulting Vec. For that, you:

  • either go from T -> T, by moving, e.g.,

    ::core::array::IntoIter::new(array) // does not work for slices unless boxed, see below
        .collect::<Vec<_>>()
    • If you are sure array is an owned array, and if your project is using the 2021 edition, then you can use array.into_iter() directly rather than ::{core,std}::array::IntoIter::new().
  • or &T -> T, by cloning, e.g.,

    array.iter() // works for slices
        .cloned() // same as `.map(Clone::clone)` or `.map(|it| it.clone())`
        .collect::<Vec<_>>()
  • or &mut T -> T, by taking / replacing, e.g.,

    array.iter_mut() // works for slices
        .map(::core::mem::take) // or .map(|it| ::core::mem::replace(it, somme_dummy))
        .collect::<Vec<_>>()

You can support moving with slices if it was behind a Box:

let _: Box<[T]> = boxed_slice;
Vec::from(boxed_slice)
  • For the sake of completeness, Box is technically not the only way to allow this. With &move / &own references, it is theoretically possible to consider:

    let _: &move [T] = owned_slice;
    Vec::from(owned_slice)

    But &move "references" are not yet part of Rust (and from the looks of it, may never be 😢). See https://docs.rs/stackbox for a cumbersome third-party implementation of those semantics, and thus more info about it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment