Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the difference between a slice and an array?

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?

like image 698
runrioter Avatar asked Jun 12 '15 01:06

runrioter


People also ask

Is an array a slice?

JavaScript Array slice()The slice() method returns selected elements in an array, as a new array. The slice() method selects from a given start, up to a (not inclusive) given end. The slice() method does not change the original array.

Is a Golang slice an array?

In Go language slice is more powerful, flexible, convenient than an array, and is a lightweight data structure. Slice is a variable-length sequence which stores elements of a similar type, you are not allowed to store different type of elements in the same slice.

What is the meaning of slicing an array?

In computer programming, array slicing is an operation that extracts a subset of elements from an array and packages them as another array, possibly in a different dimension from the original.

What is a slice data type?

slice is a composite data type and because it is composed of primitive data type (see variables lesson for primitive data types). Syntax to define a slice is pretty similar to that of an array but without specifying the elements count. Hence s is a slice.


2 Answers

[T; n] is an array of length n, represented as n adjacent T 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] where T implements Debug, and another for &T where T implements fmt::Debug, and so as u8 implements Debug, &[u8; 3] also does.

Why can &[T; n] coerce to &[T]? In Rust, when does coercion happen?

It will coerce when it needs to and at no other times. I can think of two cases:

  1. where something expects a &[T] and you give it a &[T; n] it will coerce silently;
  2. when you call 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 called starts_with.

The snippet [1, 2, 3].starts_with(&[1, 2]) demonstrates both.

like image 60
Chris Morgan Avatar answered Sep 18 '22 22:09

Chris Morgan


Why can &[T; n] coerce to &[T]?

The other answer explains why &[T; n] should coerce to &[T], here I'll explain how the compiler works out that &[T; n] can coerce to &[T].

There are four possible coercions in Rust:

  1. Transitivity.

    • If T coerces to U and U coerces to V, then T coerces to V.
  2. Pointer weakening:

    • removing mutability: &mut T&T and *mut T*const T
    • converting to raw pointer: &mut T*mut T and &T*const T
  3. Deref trait:

    • If T: Deref<Target = U>, then &T coerces to &U via the deref() method
    • (Similarly, if T: DerefMut, then &mut T coerces to &mut U via deref_mut())
  4. Unsize trait:

    • If Ptr is a "pointer type" (e.g. &T, *mut T, Box, Rc etc), and T: Unsize<U>, then Ptr<T> coerces to Ptr<U>.

    • The Unsize trait is automatically implemented for:

      • [T; n]: Unsize<[T]>
      • T: Unsize<Trait> where T: Trait
      • struct Foo<…> { …, field: T }: Unsize< struct Foo<…> { …, field: U }>, provided that T: Unsize<U> (and some more conditions to make the job easier for the compiler)
    • (Rust recognizes Ptr<X> as a "pointer type" if it implements CoerceUnsized. The actual rule is stated as, “if T: CoerceUnsized<U> then T coerces to U”.)

The reason &[T; n] coerces to &[T] is rule 4: (a) the compiler generates the implementation impl Unsize<[T]> for [T; n] for every [T; n], and (b) the reference &X is a pointer type. Using these, &[T; n] can coerce to &[T].

like image 34
kennytm Avatar answered Sep 16 '22 22:09

kennytm