Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

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;
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
616 views
Welcome To Ask or Share your Answers For Others

1 Answer

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:

  1. Borrowing vec into a temporary
  2. 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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...