What is the difference between ref and & when assigning a variable from a link?

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 is that right?

 let vec = vec![1, 2, 3]; let ref _y = &vec; 
+5
source share
3 answers

Binding to a template may get some use;)

To understand what the compiler does, you can use let _:() =...; trick. By assigning a variable of type () , you force the compiler to print an error message, telling you the type deduced 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}>' 

type y is Vec<i32> .

This means that you:

  1. Borrowing vec in temporary
  2. Trying to move vec to y , which is forbidden because vec already taken.

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}>' 

So y &&Vec<i32> .

This let's see that let ref a = b; usually equivalent to let a = &b; and therefore, in this case: let y = &&vec; ,

ref made for restructuring; for example, if you had:

 let vec = Some(vec![1, 2, 3]); if let Some(ref y) = vec { // use 'y' here } 

here you can use ref to be able to bind y to &Vec<i32> without moving, even if here vec is of type Option<Vec<i32>> . Indeed, the purpose of ref is to obtain a link inside an existing object during destructuring.

In the general case, in the let expression, you will not use ref .

+7
source

The same character ( & ) does two different things when used on the right and left side of the binding. The left side works as a pattern match, so:

 let x = (y, z); // x contains a tuple with value (y, z) let (a, b) = x // x is destructured into (a, b), so now // a has value y and b has value z 

In the same way

 let x = &y; // x is a reference to y let &z = x; // this is like let &z= &y, so we want z to be y // this is equivalent to let z = *x 

A ref binding on the left side means "match the template by reference, not by value." So these two statements are equivalent:

 let ref y = vec; let y = &vec; 

although in let, the second is more idiomatic.

You can see more examples of rust pointers / links on an example.

+2
source

First of all, you do not need & in your working example. If you use it, you will get a &&Vec<_> , which you really don't need.

 let vec = vec![1, 2, 3]; let ref y = vec; 

The problem with your first code is that you are doing two things at once. Let's divide it into two parts:

The first part creates a link to vec

 let y1 = &vec; 

The second part ( & before variable binding), destruction .

 let &y2 = y1; 

This means that you are trying to exit the link, which only works if the type is Copy , because then any attempt to move will copy the object.

+1
source

Source: https://habr.com/ru/post/1240317/


All Articles