Dot Operator

The useful methods on arrays—iterating over elements, searching, sorting, filling, filtering, and so on—are all provided as methods on slices, not arrays. Rust implicitly converts an array to a slice when searching for methods.

Consider the following code:

1
2
3
4
5
let v: Vec<f64> = vec![0.0, 0.707, 1.0, 0.707];     // v on stack, data on heap
let a: [f64; 4] =     [0.0, -0.707, -1.0, -0.707];  // stack

let sv: &[f64] = &v;
let sa: &[f64] = &a;

In the last two lines, Rust automatically converts the &Vec<f64> reference and the &[f64; 4] reference to slice references that point directly to the data. By the end, memory looks like this:

A vector `v` and an array `a` in memory, with slices `sa` and `sv` referring to each

The reverse method is actually defined on slices, but the call implicitly borrows a &mut [&str] slice from the vector and invokes reverse on that:

1
2
3
let mut palindrome = vec!["a man", "a plan", "a canal", "panama"];
palindrome.reverse();
assert_eq!(palindrome, vec!["panama", "a canal", "a plan", "a man"]);

Rust implicitly produces a &mut [i32] slice referring to the entire array and passes that to sort to operate on:

1
2
3
let mut chaos = [3, 5, 4, 1, 2];
chaos.sort();
assert_eq!(chaos, [1, 2, 3, 4, 5]);

References

In Rust, references are created explicitly with the & operator, and dereferenced explicitly with the * operator. The . operator is an exception. It borrows and dereferences implicitly.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
let mut v = vec![1973, 1968];
v.sort();           // implicitly borrows a mutable reference to v
(&mut v).sort();    // equivalent, but more verbose


struct Anime { name: &'static str, bechdel_pass: bool };
let aria = Anime { name: "Aria: The Animation", bechdel_pass: true };
let anime_ref = &aria;
assert_eq!(anime_ref.name, "Aria: The Animation"); // deference implicitly

// Equivalent to the above, but with the dereference written out:
assert_eq!((*anime_ref).name, "Aria: The Animation");

Deref Coercions

A conversion usually requires a cast. A few conversions involving reference types are so straightforward that the language performs them even without a cast:

  • Values of type &String auto-convert to type &str without a cast.
  • Values of type &Vec<i32> auto-convert to &[i32].
  • Values of type &Box<Chessboard> auto-convert to &Chessboard.
  • Values of a mut reference auto-convert to a non-mut reference without a cast.

These are called deref coercions, because they apply to types that implement the Deref built-in trait. The purpose of Deref coercion is to make smart pointer types, like Box, behave as much like the underlying value as possible. Using a Box<Chessboard> is mostly just like using a plain Chessboard, thanks to Deref.