ref和& amp;之间的区别是什么?从参考中分配变量时?

时间:2016-01-11 08:30:31

标签: syntax reference rust pattern-matching

此代码有什么问题?

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;
  |          ^^

为什么这是正确的?

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

3 个答案:

答案 0 :(得分:8)

模式绑定可以使用;)

为了理解编译器的功能,您可以使用let _: () = ...;技巧。通过分配类型为()的变量,可以强制编译器打印一条错误消息,为您提供为变量推断的类型。

在第一个例子中:

let vec = vec![1, 2, 3];
let &y = &vec;
let _: () = y;

我们得到:

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

y的类型为Vec<i32>

这意味着你是:

  1. 借用vec暂时
  2. 试图将vec移至y,因为vec已被借用而被禁止。
  3. 等效的正确代码是:

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

    在第二个例子中:

    let vec = vec![1, 2, 3];
    let ref y = &vec;
    let _: () = y;
    

    我们得到:

      
    error[E0308]: mismatched types
     --> src/lib.rs:4:17
      |
    4 |     let _: () = y;
      |                 ^ expected (), found reference
      |
      = note: expected type `()`
                 found type `&&std::vec::Vec<{integer}>`
    

    因此y&&Vec<i32>

    这让我们看到let ref a = b;通常等同于let a = &b;,因此在这种情况下:let y = &&vec;

    ref用于解构;例如,如果你有:

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

    您可以在ref使用y将<{1}}绑定到&Vec<i32> 而不移动,即使vec此处的类型为{{1} }}。实际上,Option<Vec<i32>>的目的是在解构期间在内部引用

    通常,在ref语句中,您不会使用let

    自Rust 1.26起,ref在模式匹配中得到推断;请参阅stabilization of match ergonomics

答案 1 :(得分:2)

当在绑定的右端和左端使用时,相同的符号(&)正在做两件事。左侧的工作方式类似于模式匹配,所以:

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

以同样的方式

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

左侧的ref绑定表示&#34;模式匹配参考,而不是值&#34;。所以这两个陈述是等价的:

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

虽然在一个让,第二个是更惯用。

您可以在pointers/ref chapter on rust by example

上看到更多示例

答案 2 :(得分:1)

首先,您的工作示例中不需要&。如果您使用它,最终会得到&&Vec<_>,这是您真正不需要的。

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

您的第一个代码的问题是您一次做两件事。让我们把它分成两部分:

第一部分创建对vec

的引用
let y1 = &vec;

第二部分(变量绑定前的&),destructures

let &y2 = y1;

这意味着您正在尝试移出引用,该引用仅在类型为Copy时有效,因为任何移动尝试都将复制该对象。