Why can we coerce an array to a slice

I came across a sample code from rust std doc:

let slice = &[1, 1, 1, 3, 3, 2, 2, 2];

let mut iter = slice.chunk_by(|a, b| a == b);

assert_eq!(iter.next(), Some(&[1, 1, 1][..]));
assert_eq!(iter.next(), Some(&[3, 3][..]));
assert_eq!(iter.next(), Some(&[2, 2, 2][..]));
assert_eq!(iter.next(), None);

And I noticed if I changed it to Some(&[1, 1, 1]), it wouldn't compile because it's now only a reference to an array, not a slice. I previously thought reference to an array was the same as slice. This is fine, because I looked up the doc and saw this code at the beginning of the page:

// slicing a Vec
let vec = vec![1, 2, 3];
let int_slice = &vec[..];
// coercing an array to a slice
let str_slice: &[&str] = &["one", "two", "three"];

And it says "coercing an array to a slince", which means they're not the same. But then I looked up the doc of Deref trait, and I didn't found array type implements Deref trait. Nothing similar actually did so. So how can we coerce array (or a reference to array) into slice if array doesn't implement Deref? ( Maybe something that includes array type actually implements it. But I'm just not familiar with all the contents of Rust, so if I missed it, please just point it out)

1 Like

This is type inference not being able to infer through a wrapping type—Option<_> in your case—when the wrapped type needs to be coerced in some way.

Besides your [..] workaround,

assert_eq!(iter.next().unwrap(), &[1, 1, 1]);

also works or using the as _ trick to nudge type inference a bit:

assert_eq!(iter.next(), Some(&[1, 1, 1] as _));

So is Deref trait just not relevant, and it's all about type inference?

You can coerce [u32; N] to [u32] through unsizing, so no Deref implementation needed.

2 Likes

Check the list of coercion types in the reference: Type coercions - The Rust Reference

The relevant entry for array to slice is towards the bottom of that list where it mentions "unsized coercion".

2 Likes

I think the relevant rules in the reference are

  • TyCtor(T) to TyCtor(U), where TyCtor(T) is one of

    • &T
    • &mut T
    • *const T
    • *mut T
    • Box<T>

    and where U can be obtained from T by unsized coercion.

and the following section about so called unsized coercions:

The following coercions are built-ins and, if T can be coerced to U with one of them, then an implementation of Unsize<U> for T will be provided:

  • [T; n] to [T].
  • [Cut for brevity]

It can be a bit confusing, because T is used for different things here. But bascially rule 2 says that arrays can be coerced to slices, and rule 1 says that therefore &array can be coerced to &slice. (with the narrow definition of a slice meaning [T] and not &[T], which can also be confusing)

5 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.