This is the effect of destructuring. I won't completely describe that feature here, but in short:
In many syntax contexts (let
bindings, for
loops, function arguments, ...) , Rust expects a "pattern". This pattern can be a simple variable name, but it can also contain some "destructuring elements", like &
. Rust will then bind a value to this pattern. A simple example would be something like this:
let (a, b) = ('x', true);
On the right hand side there is a value of type (char, bool)
(a tuple). This value is bound to the left hand pattern ((a, b)
). As there is already a "structure" defined in the pattern (specifically, the tuple), that structure is removed and a
und b
bind to the tuple's elements. Thus, the type of a
is char
and the type of b
is bool
.
This works with a couple of structures, including arrays:
let [x] = [true];
Again, on the right side we have a value of type [bool; 1]
(an array) and on the left side we have a pattern in the form of an array. The single array element is bound to x
, meaning that the type of x
is bool
and not [bool; 1]
!
And unsurprisingly, this also works for references!
let foo = 0u32;
let r = &foo;
let &c = &foo;
Here, foo
has the type u32
and consequently, the expression &foo
has the type &u32
. The type of r
is also &u32
, as it is a simple let
binding. The type of c
is u32
however! That is because the "reference was destructured/removed" by the pattern.
A common misunderstanding is that syntax in patterns has exactly the opposite effect of what the same syntax would have in expressions! If you have a variable a
of type [T; 1]
, then the expression [a]
has the type [[T; 1]; 1]
→ it adds stuff. However, if you bind a
to the pattern [c]
, then y
has the type T
→ it removes stuff.
let a = [true]; // type of `a`: `[bool; 1]`
let b = [a]; // type of `b`: `[[bool; 1]; 1]`
let [c] = a; // type of `c`: `bool`
This also explains your question:
It seems like it is somehow dereferencing, but then why in the below code, it is not working?
fn main() {
let mut hey:i32 = 32;
let x:i32 = 2;
hey = &&x;
}
Because you use &
on the expression side, where it adds a layer of references.
So finally about your loop: when iterating over a slice (as you do here), the iterator yields reference to the slice's elements. So in the case for i in list {}
, i
has the type &i32
. But the assignment largest = i;
requires a i32
on the right hand side. You can achieve this in two ways: either dereference i
via the dereference operator *
(i.e. largest = *i;
) or destructure the reference in the loop pattern (i.e. for &i in list {}
).
Related questions: