Why does the following code fail to compile?

fn main() {
  let a1 = &[1usize, 2, 3];
  let a2 = &[1usize, 2, 3, 4, 5];
  let v = [a1, a2];
  println!("{v:?}");
}

The above Rust code fails to compile giving the following error message.

  Compiling playground v0.0.1 (/playground)
error[E0308]: mismatched types
 --> src/main.rs:5:16
  |
5 |   let v = [a1, a2];
  |                ^^ expected an array with a fixed size of 3 elements, found one with 5 elements

For more information about this error, try `rustc --explain E0308`.
error: could not compile `playground` due to previous error

However, if I manually specify a1 and a2 as slices, it compiles.

fn main() {
  let a1: &[_] = &[1usize, 2, 3];
  let a2: &[_] = &[1usize, 2, 3, 4, 5];
  let v = [a1, a2];
  println!("{v:?}");
}

Does this mean that &[1usize, 2, 3] is not a type of slice but can be implicitly casted to a slice when needed?

Yes, they are constant-size arrays of type [usize; 3] and [usize; 5], respectively – just like the error message itself says.

Just to clarify, you mean they are "references" to constant-size arrays, right?

The literals are arrays, and the variables a1 and a2 are references to them.

In case it helps clarify...

&[1, 2, 3] (without further context):

+-----+ // "Thin" pointer to an array
+ ptr | // Size: one `usize` big
+-----+ // Type: &[i32; 3] (different lengths implies different types)
|
V 
+---+---+---+ // Size: statically known to be 12
| 1 | 2 | 3 | // Length: statically known be 3
+---+---+---+ // Type: [i32; 3] (different lengths implies different types)

&[1, 2, 3][..], &[1, 2, 3] as &[_]:

+-----+-----+ // "Wide" pointer to a slice (wide due to the length)
+ ptr | len | // Size: two `usize`s big
+-----+-----+ // Type: &[i32] (all lengths have the same type)
|
V 
+---+---+---- // Size: statically unknown! (depends on the length)
| 1 | 2 | ... // Length: statically unknown! (stored in the wide pointer)
+---+---+---- // Type: [i32] (all lengths have the same type)

A reference to a slice (&[T]) is often just still called a slice. Because they're dynamically sized, a slice ([T]) is generally seen behind some sort of pointer (&[T], Box<[T]>, Arc<[T]>, ...). Arrays don't have that restriction.

A &[T; N] can coerce to a &[T].

10 Likes

Awesome! Thank you for your clear explanations!

Thank you for such a detailed answer!

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.