Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get a slice as an array in Rust?

Tags:

arrays

rust

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?

like image 756
Jeroen Avatar asked Aug 21 '14 14:08

Jeroen


People also ask

Does slice work on array?

JavaScript Array slice()The slice() method returns selected elements in an array, as a new array. The slice() method selects from a given start, up to a (not inclusive) given end. The slice() method does not change the original array.

How do you make an array in Rust?

In Rust, arrays are created using square brackets [] and their size needs to be known at compile time. An array whose size is not defined is called a slice.

How do you add slices in Rust?

As a result, you cannot use a Rust slice to insert, append or remove elements from the underlying container. Instead, you need either: to use a mutable reference to the container itself, to design a trait and use a mutable reference to said trait.

How do you add to an array in Rust?

There is no way to do this in stable Rust; arrays cannot have values added or removed at runtime; their lengths are fixed at compile time.


2 Answers

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

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] 
like image 74
Lukas Kalbertodt Avatar answered Sep 28 '22 07:09

Lukas Kalbertodt


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.

like image 36
Matthieu M. Avatar answered Sep 28 '22 07:09

Matthieu M.