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?
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.
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.
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.
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.
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]
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With