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

前端 未结 3 1540
一生所求
一生所求 2020-12-19 07:32

What is wrong with this code?

fn example() {
    let vec = vec![1, 2, 3];
    let &_y = &vec;
}


        
3条回答
  •  既然无缘
    2020-12-19 08:32

    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.

    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.

    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 without moving even though vec here has type Option>. 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.

提交回复
热议问题