116

Is there a good way to convert a Vec<T> with size S to an array of type [T; S]? Specifically, I'm using a function that returns a 128-bit hash as a Vec<u8>, which will always have length 16, and I would like to deal with the hash as a [u8, 16].

Is there something built-in akin to the as_slice method which gives me what I want, or should I write my own function which allocates a fixed-size array, iterates through the vector copying each element, and returns the array?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
jgray
  • 1,173
  • 2
  • 7
  • 4
  • 3
    it's one line. use itertools:Itertools; my_array.iter_mut().set_from(my_vector.iter().cloned()); – don bright Jan 12 '19 at 04:44
  • @donbright doesn t this result in a memory allocation? – user2284570 Dec 27 '20 at 11:39
  • i am sorry im not 100% sure what you mean.... you can view the generated assembler here (click the ... by Run and hit ASM): https://play.rust-lang.org/?version=stable&mode=release&edition=2018&gist=088605093493b42833e08b8698841f20 – don bright Dec 27 '20 at 19:36
  • looking back at this now, the user, depending on intended platform, may be able to use a unsafe transmute, which would in theory eliminate copying ("memory allocation"?) .. and allow to use the bytes as-is – don bright Dec 27 '20 at 19:52
  • `as_chunks` method does the trick. Experimental at the moment writing this. – Anssi May 14 '22 at 11:01

1 Answers1

114

Arrays must be completely initialized, so you quickly run into concerns about what to do when you convert a vector with too many or too few elements into an array. These examples simply panic.

As of Rust 1.51 you can parameterize over an array's length.

use std::convert::TryInto;

fn demo<T, const N: usize>(v: Vec<T>) -> [T; N] {
    v.try_into()
        .unwrap_or_else(|v: Vec<T>| panic!("Expected a Vec of length {} but it was {}", N, v.len()))
}

As of Rust 1.48, each size needs to be a specialized implementation:

use std::convert::TryInto;

fn demo<T>(v: Vec<T>) -> [T; 4] {
    v.try_into()
        .unwrap_or_else(|v: Vec<T>| panic!("Expected a Vec of length {} but it was {}", 4, v.len()))
}

As of Rust 1.43:

use std::convert::TryInto;

fn demo<T>(v: Vec<T>) -> [T; 4] {
    let boxed_slice = v.into_boxed_slice();
    let boxed_array: Box<[T; 4]> = match boxed_slice.try_into() {
        Ok(ba) => ba,
        Err(o) => panic!("Expected a Vec of length {} but it was {}", 4, o.len()),
    };
    *boxed_array
}

See also:

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
  • For me, this fails with `the trait \`std::convert::From>\` is not implemented for \`std::boxed::Box<[T; 3]>\``. Is this new? (The vector I supply is size 3, and I've changed the "demo" function accordingly). – Alien_AV Sep 28 '20 at 16:27
  • 1
    @Alien_AV [works for me](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=779b1789e20d5fda0ac16f0db669fded). – Shepmaster Sep 28 '20 at 16:33