Q:

What's the difference between ref and & when assigning a variable from a reference?

What is wrong with this code?
fn example() {
    let vec = vec![1, 2, 3];
    let &_y = &vec;
}

error[E0507]: cannot move out of borrowed content
 --> src/lib.rs:3:15
  |
3 |     let &_y = &vec;
  |         ---   ^^^^ cannot move out of borrowed content
  |         ||
  |         |data moved here
  |         help: consider removing the `&`: `_y`
  |
note: move occurs because `_y` has type `std::vec::Vec<i32>`, which does not implement the `Copy` trait
 --> src/lib.rs:3:10
  |
3 |     let &_y = &vec;
  |          ^^

and why this is correct?
let vec = vec![1, 2, 3];
let ref _y = &vec;

A:

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.

