you’re using a so-called pattern. Pattern matching in Rust is most prominent in match syntax, or if let …, but normal let supports certain patterns, too. Mutability markers (i.e. the mut of let mut x = …) is also part of pattern syntax btw.
Anyway, there’s the &… pattern which matches against a reference, dereferences it, and matches the result against the pattern ….
Hence
let &r = &i;
has the effect of taking the reference &i (of type &i32), dereferencing it, and then assigning the resulting i32 to a new variable r.
With
let &(mut r) = &i;
instead, that new variable is also mutable.
You don’t really need to use this syntax though, it’s perhaps easier to just dereference using the * operator on the right side of the let statement.
// instead of
let &r = &i;
// you can do
let r = *&i;
// or in this case
let r = i;
// because the `*` and `&` steps effectively “cancel out”
// instead of
let &(mut r) = &i;
// you can do
let mut r = *&i;
// or in this case
let mut r = i;
It’s essentially the same thing in both cases, the context is important.
In the first example, number_list is a Vec<i32>. In the second example, list is a function argument of type &[i32]. If you ignore the Vec<i32> vs. [i32] distinction, notably, in the second case listalready is a reference.
It doesn’t have to always be a reference. Iteration with for in Rust (which works with any type supporting the IntoIterator trait) typically supports 3 different modes: by value, consuming the collection and yielding owned items, by-reference, taking the collection by reference, and yielding &T items, and by mutable reference (same idea as before, but add the word “mutable” everywhere).
These examples each used a reference (&Vec<i32> or &[i32]) to a collection, so the type of number/item will be &i32, too.