Why are both &[u8]
and &[u8; 3]
ok in this example?
fn main() {
let x: &[u8] = &[1u8, 2, 3];
println!("{:?}", x);
let y: &[u8; 3] = &[1u8, 2, 3];
println!("{:?}", y);
}
The fact that
&[T; n]
can coerce to&[T]
is the aspect that makes them tolerable. — Chris Morgan
Why can &[T; n]
coerce to &[T]
? In what other conditions does this coercion happen?
[T; n]
is an array of lengthn
, represented asn
adjacentT
instances.&[T; n]
is purely a reference to that array, represented as a thin pointer to the data.[T]
is a slice, an unsized type; it can only be used through some form of indirection.&[T]
, called a slice, is a sized type. It's a fat pointer, represented as a pointer to the first item and the length of the slice.Arrays thus have their length known at compile time while slice lengths are a runtime matter. Arrays are second class citizens at present in Rust, as it is not possible to form array generics. There are manual implementations of the various traits for
[T; 0]
,[T; 1]
, &c., typically up to 32; because of this limitation, slices are much more generally useful. The fact that&[T; n]
can coerce to&[T]
is the aspect that makes them tolerable.There is an implementation of
fmt::Debug
for[T; 3]
whereT
implementsDebug
, and another for&T
whereT
implementsfmt::Debug
, and so asu8
implementsDebug
,&[u8; 3]
also does.It will coerce when it needs to and at no other times. I can think of two cases:
&[T]
and you give it a&[T; n]
it will coerce silently;x.starts_with(…)
on a[T; n]
it will observe that there is no such method on[T; n]
, and so autoref comes into play and it tries&[T; n]
, which doesn’t help, and then coercion come into play and it tries&[T]
, which has a method calledstarts_with
.The snippet
[1, 2, 3].starts_with(&[1, 2])
demonstrates both.