Convert slice &[u8] to &[u8; 4]

For example:

fn main() {
    let array = [0u8, 0u8, 0u8, 1u8, 0u8, 0u8, 0u8, 1u8];
    let a1 : &[u8;4] = &array[0..4];

the compiler reported that

error[E0308]: mismatched types
 --> src/
3 |     let a1 : &[u8;4] = &array[0..4];
  |              -------   ^^^^^^^^^^^^ expected array `[u8; 4]`, found slice `[u8]`
  |              |
  |              expected due to this
  = note: expected reference `&[u8; 4]`
             found reference `&[u8]`

I'm curious why my &array[0..4] is not a &[u8;4] type? And in this cause, is using transmute the only way?

You can use array[0..4].try_into().unwrap() since there is an impl<'a, T, const N: usize> TryFrom<&'a [T]> for &'a [T; N] in the standard library.

It's because the indexing operation has the signature (&[T; N], Range) -> &[T], and nothing in the return type says that the length will be exactly 4. Of course in this case you're indexing with a literal, so if the operation doesn't panic then the returned slice is guaranteed to have length 4, a compile-time constant, but the compiler doesn't have the machinery to reason that way presently; it would require a new trait beyond std::ops::Index with a &[T; M] return type, and a desugaring for the array[0..4] syntax that invokes the new trait.

Edit: transmute here would be unsound since &[T] and &[T; 4] do not have the same layout! (Fat pointer vs. thin pointer.) In fact, transmute will just panic when you ask it to do this.


This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.