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/main.rs:3:24
  |
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.

6 Likes

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.