Rust 实例:ref 模式

Rust by example: The ref pattern

我无法理解 Rust 中的 ref 模式。我指的是 https://rustbyexample.com/scope/borrow/ref.html

这是我不明白的代码:

let point = Point { x: 0, y: 0 };

let _copy_of_x = {
    // `ref_to_x` is a reference to the `x` field of `point`
    let Point { x: ref ref_to_x, y: _ } = point;

    // Return a copy of the `x` field of `point`
    *ref_to_x
};

我知道最后一个 let 表达式 (?) 是某种模式匹配。所以我的理解ref ref_to_x应该等于0,原来pointx值。

但我不明白 ref 的实际作用。当我添加这样的代码时:

println!("x: {}", point.x);
println!("ref_to_x: {}", ref_to_x);
println!("*ref_to_x: {}", *ref_to_x);

我总是得到0,所以似乎没有什么区别。不知何故,我希望 ref_to_x 有一个内存地址,而 *ref_to_x 可能又是取消引用的值。

我可以用 myx 替换 ref ref_to_x*ref_to_x,代码仍然有效。有什么不同? ref 究竟是做什么的?

编辑:在阅读了 dbaupps 的回答并用 ref_to_x*ref_to_x 做了一些补充之后,事情变得更清楚了;您不能将整数添加到 ref_to_x,因为它是一个引用。我想我很困惑,因为当你打印一个时没有参考的迹象。

ref创建一个指针指向正在匹配的那块内存,在这种情况下,ref_to_x直接指向存储point.x的内存,它是在这种情况下与写 let ref_to_x = &point.x 相同。

该模式非常重要,因为它允许人们深入了解复杂的数据结构,而不会扰乱所有权层次结构。例如,如果一个人有val: &Option<String>,写作

match *val {
    Some(s) => println!("the string is {}", s),
    None => println!("no string"
}

是不合法的,它会给出如下错误:

<anon>:3:11: 3:15 error: cannot move out of borrowed content
<anon>:3     match *val {
                   ^~~~
<anon>:4:14: 4:15 note: attempting to move value to here
<anon>:4         Some(s) => {}
                      ^
<anon>:4:14: 4:15 help: to prevent the move, use `ref s` or `ref mut s` to capture value by reference
<anon>:4         Some(s) => {}
                      ^

从借用的值中获取所有权(移动)是不合法的,因为这可能会损坏借用值的对象(违反其不变量,导致数据意外消失等)。

因此,可以改用引用来仅通过借用 & 引用指向内存。


这里有一点微妙之处,因为 (a) point 不是借来的,所以可以搬出 point(这也会消耗 point 的所有权,意思是它不能在以后使用,除非重新初始化),并且 (b) 类型 intCopy,因此在按值使用时不会移动所有权。这就是为什么使用 myx 可以正常工作的原因。如果 x 的类型是 String(不是 Copy)并且 point 是借用的,那么 ref 将是必要的。

使用 ref 创建的引用与使用 & 创建的引用完全相同。

区别在于它们在语法中的允许位置。 ref 在赋值的左侧就像在右侧添加 &

这些表达式是等价的:

let ref x1 = y;
let x2 = &y;

存在这种冗余是因为在模式匹配中 & 用于要求引用已经存在,而不是创建一个新引用:

let foo = 1;
match foo {
   ref x => {
       /* x == &1 */ 
       match x {
           &y => /* y == 1 */
       }
   },  
}

(discussion)