Tuple of slices

So here we have an elementary Rust construct.

    let a = &[1,2,3,4];
    let b = &[5,6,7,8];

a and b are slices, right. Says so right here in the manual.. So then I write:

`let c = (a, b);`

So that should be a tuple of slices, correct? It's not.

   Compiling playground v0.0.1 (/playground)
error[E0308]: mismatched types
  --> src/main.rs:17:21
   |
17 |     tuple_of_slices(c); // this complains.
   |                     ^ expected slice `[u32]`, found array `[u32; 4]`
   |
   = note: expected tuple `(&[u32], &[u32])`
              found tuple `(&[u32; 4], &[{integer}; 4])`

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

So how did c become a tuple of fixed sized arrays?

This seems to be type inference getting confused. An explicit declaration

let c: (&[u32],&[u32]) = (a, b);

will fix the problem. It's puzzling that type inference got it wrong. All the info was available, and the only use made of the value put it into a function that expected (&[u32],&[u32]).

No, they are reference to arrays. The [] constructor syntax is for array literals.

No, the manual correctly states that they are arrays:

Arrays are created using brackets []

It didn't.

Well no, actually, they're references to arrays.

The compiler will tell you this if you annotate the type intentionally-wrong:

error[E0308]: mismatched types
 --> src/main.rs:2:17
  |
2 |     let a: () = &[1,2,3,4];
  |            --   ^^^^^^^^^^ expected `()`, found `&[{integer}; 4]`
  |            |
  |            expected due to this

error[E0308]: mismatched types
 --> src/main.rs:3:17
  |
3 |     let b: () = &[5,6,7,8];
  |            --   ^^^^^^^^^^ expected `()`, found `&[{integer}; 4]`
  |            |
  |            expected due to this

(That's a great way to find out the type of things -- you can also do as () or various other similar things, and the error message will let you know.)

In the book it says

// This function borrows a slice
fn analyze_slice(slice: &[i32]) {

And mentions that

    // Arrays can be automatically borrowed as slices
    println!("borrow the whole array as a slice");
    analyze_slice(&xs);

That's because there's an automatic coercion from &[T; N] to &[T].

But there isn't an automatic coercion from (&[T; N], &[T; N]) to (&[T], &[T]), which is the error you're hitting.

The general version of this problem is that coercions and type inference just fundamentally don't mix.

So you can force the coercion to happen by putting a type annotation somewhere else, such as

    let a = &[1,2,3,4];
    let b = &[5,6,7,8];
    let c: (&[_], &[_]) = (a, b); // <-- note new type annotation

At which point it compiles.

5 Likes

You can als make the slices directly, by writing

let a = &[1,2,3,4][..];
let b = &[5,6,7,8][..];

Rust Playground

2 Likes

Or

let a = [1,2,3,4].as_slice();
let b = [5,6,7,8].as_slice();
1 Like