How to get a slice as an array in Rust?

ArraysRust

Arrays Problem Overview


I have an array of an unknown size, and I would like to get a slice of that array and convert it to a statically sized array:

fn pop(barry: &[u8]) -> [u8; 3] {
    barry[0..3] // expected array `[u8; 3]`, found slice `[u8]`
}

How would I do this?

Arrays Solutions


Solution 1 - Arrays

You can easily do this with the TryInto trait (which was stabilized in Rust 1.34):

// Before Rust 2021, you need to import the trait:
// use std::convert::TryInto;

fn pop(barry: &[u8]) -> [u8; 3] {
    barry.try_into().expect("slice with incorrect length")
}

But even better: there is no need to clone/copy your elements! It is actually possible to get a &[u8; 3] from a &[u8]:

fn pop(barry: &[u8]) -> &[u8; 3] {
    barry.try_into().expect("slice with incorrect length")
}

As mentioned in the other answers, you probably don't want to panic if the length of barry is not 3, but instead handle this error gracefully.

This works thanks to these impls of the related trait TryFrom (before Rust 1.47, these only existed for arrays up to length 32):

impl<'_, T, const N: usize> TryFrom<&'_ [T]> for [T; N]
where
    T: Copy, 

impl<'a, T, const N: usize> TryFrom<&'a [T]> for &'a [T; N]

impl<'a, T, const N: usize> TryFrom<&'a mut [T]> for &'a mut [T; N]

Solution 2 - Arrays

Thanks to @malbarbo we can use this helper function:

use std::convert::AsMut;

fn clone_into_array<A, T>(slice: &[T]) -> A
where
    A: Default + AsMut<[T]>,
    T: Clone,
{
    let mut a = A::default();
    <A as AsMut<[T]>>::as_mut(&mut a).clone_from_slice(slice);
    a
}

to get a much neater syntax:

fn main() {
    let original = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

    let e = Example {
        a: clone_into_array(&original[0..4]),
        b: clone_into_array(&original[4..10]),
    };

    println!("{:?}", e);
}

as long as T: Default + Clone.

If you know your type implements Copy, you can use this form:

use std::convert::AsMut;

fn copy_into_array<A, T>(slice: &[T]) -> A
where
    A: Default + AsMut<[T]>,
    T: Copy,
{
    let mut a = A::default();
    <A as AsMut<[T]>>::as_mut(&mut a).copy_from_slice(slice);
    a
}

Both variants will panic! if the target array and the passed-in slice do not have the same length.

Solution 3 - Arrays

I recommend using the crate arrayref, which has a handy macro for doing just this.

Note that, using this crate, you create a reference to an array, &[u8; 3], because it doesn't clone any data!

If you do want to clone the data, then you can still use the macro, but call clone at the end:

#[macro_use]
extern crate arrayref;

fn pop(barry: &[u8]) -> &[u8; 3] {
    array_ref!(barry, 0, 3)
}

or

#[macro_use]
extern crate arrayref;

fn pop(barry: &[u8]) -> [u8; 3] {
    array_ref!(barry, 0, 3).clone()
}

Solution 4 - Arrays

Here's a function that matches the type signature you asked for.

fn pop(barry: &[u8]) -> [u8; 3] {
    [barry[0], barry[1], barry[2]]
}

But since barry could have fewer than three elements, you may want to return an Option<[u8; 3]> rather than a [u8; 3].

fn pop(barry: &[u8]) -> Option<[u8; 3]> {
    if barry.len() < 3 {
        None
    } else {
        Some([barry[0], barry[1], barry[2]])
    }
}

Solution 5 - Arrays

You can manually create the array and return it.

Here is a function that can easily scale if you want to get more (or less) than 3 elements.

Note that if the slice is too small, the end terms of the array will be 0's.

fn pop(barry: &[u8]) -> [u8; 3] {
    let mut array = [0u8; 3];
    for (&x, p) in barry.iter().zip(array.iter_mut()) {
        *p = x;
    }
    array
}

Solution 6 - Arrays

I was unhappy with other answers because I needed several functions that return varying length fixed u8 arrays. I wrote a macro that produces functions specific for the task. Hope it helps someone.

#[macro_export]
macro_rules! vec_arr_func {
    ($name:ident, $type:ty, $size:expr) => {
        pub fn $name(data: std::vec::Vec<$type>) -> [$type; $size] {
            let mut arr = [0; $size];
            arr.copy_from_slice(&data[0..$size]);
            arr
        }
    };
}

//usage - pass in a name for the fn, type of array, length
vec_arr_func!(v32, u8, 32);
v32(data); //where data is std::vec::Vec<u8>

Solution 7 - Arrays

The nice common thing between Vec, 'Slice' and Array is Iter, so you can zip and map both together, as simple as:

let x = vec![1, 2, 3];
let mut y: [u8; 3] = [Default::default(); 3];
println!("y at startup: {:?}", y);    
x.iter().zip(y.iter_mut()).map(|(&x, y)| *y = x).count();
println!("y copied from vec: {:?}", y);

enter image description here

This is as the array is 1 dimensional array.

To test all together, vec, slice and array, here you go:

let a = [1, 2, 3, 4, 5];
let slice = &a[1..4];
let mut x: Vec<u8> = vec![Default::default(); 3];
println!("X at startup: {:?}", x);    
slice.iter().zip(x.iter_mut()).map(|(&s, x)| *x = s).count();
println!("X copied from vec: {:?}", x);

enter image description here

Another option which should be faster than byte-by-byte copy is:

y[..x.len()].copy_from_slice(&x);

Which is applicable for all, below is example:

let a = [1, 2, 3, 4, 5];
let mut b: Vec<u8> = vec![Default::default(); 5];
b[..a.len()].copy_from_slice(&a);
println!("Copy array a into vector b: {:?}", b);

let x: Vec<u8> = vec![1, 2, 3, 4, 5];
let mut y: [u8; 5] = [Default::default(); 5];
y[..x.len()].copy_from_slice(&x);
println!("Copy vector x into array y: {:?}", y);

enter image description here

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJeroenView Question on Stackoverflow
Solution 1 - ArraysLukas KalbertodtView Answer on Stackoverflow
Solution 2 - ArraysMatthieu M.View Answer on Stackoverflow
Solution 3 - ArrayspaholgView Answer on Stackoverflow
Solution 4 - ArraysmwhittakerView Answer on Stackoverflow
Solution 5 - ArraysLevansView Answer on Stackoverflow
Solution 6 - ArraysmattdlockyerView Answer on Stackoverflow
Solution 7 - ArraysHasan A YousefView Answer on Stackoverflow