Pattern binding can get some using to ;)
In order to understand what the compiler does, you can use the let _: () = ...; trick. By assigning to a variable of type (), you force the compiler to print an error message giving you the type it inferred for your variable.
In the first example:
let vec = vec![1, 2, 3];
let &y = &vec;
let _: () = y;
we get:
error[E0308]: mismatched types
--> src/lib.rs:4:13
|
4 | let _: () = y;
| ^ expected (), found struct `std::vec::Vec`
|
= note: expected type `()`
found type `std::vec::Vec<{integer}>`
the type of y is Vec<i32>.
What it means is that you are:
- Borrowing
vec into a temporary
- Attempting to move
vec into y, which is forbidden because vec is already borrowed.
The equivalent correct code would be:
let vec = vec![1, 2, 3];
let y = vec;
In the second example:
let vec = vec![1, 2, 3];
let ref y = &vec;
let _: () = y;
we get:
error[E0308]: mismatched types
--> src/lib.rs:4:17
|
4 | let _: () = y;
| ^ expected (), found reference
|
= note: expected type `()`
found type `&&std::vec::Vec<{integer}>`
Thus y is &&Vec<i32>.
This let us see that let ref a = b; is generally equivalent to let a = &b;, and therefore in this case: let y = &&vec;.
ref is made for destructuring; for example, if you had:
let vec = Some(vec![1, 2, 3]);
if let Some(ref y) = vec {
// use `y` here
}
you can use ref here to be able to bind y to &Vec<i32> without moving even though vec here has type Option<Vec<i32>>. Indeed, the purpose of ref is to take a reference inside an existing object during destructuring.
In general, in a let statement, you will not use ref.
And since Rust 1.26, ref is inferred in pattern matching; see the stabilization of match ergonomics.