Rust 示例:参考模式 [英] Rust by example: The ref pattern

查看:36
本文介绍了Rust 示例:参考模式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在理解 Rust 中的 ref 模式时遇到问题.我指的是 https://rustbyexample.com/scope/borrow/ref.html

这是我不明白的代码:

let point = Point { x: 0, y: 0 };让_copy_of_x = {//`ref_to_x` 是对 `point` 的 `x` 字段的引用让点 { x: ref ref_to_x, y: _ } = 点;//返回 `point` 的 `x` 字段的副本*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,写

匹配 *val {一些=>println!("字符串是{}", s),无 =>println!("没有字符串"}

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

:3:11: 3:15 错误:无法移出借来的内容:3 匹配 *val {^~~~<anon>:4:14: 4:15 注意:试图将值移到这里<anon>:4 Some(s) =>{}^<anon>:4:14: 4:15 help: 为了防止移动,使用`ref s`或`ref mut s`来通过引用捕获值<anon>:4 Some(s) =>{}^

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

因此,您可以使用引用来仅通过借用 & 引用指向内存.

<小时>

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

I have problems understanding the ref pattern in Rust. I am referring to https://rustbyexample.com/scope/borrow/ref.html

Here is the code I don't understand:

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

I get that the last let expression(?) is some sort of pattern matching. So it's my understanding ref ref_to_x should be equal to 0, the x value of the original point.

But I don't understand what the ref actually does. When I add some code like this:

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

I always get 0, so there doesn't seem to be a difference. Somehow I'd expect a memory address for ref_to_x while *ref_to_x might be the dereferenced value again.

I can replace both ref ref_to_x and *ref_to_x with myx and the code still works. What's the difference? What does ref do exactly?

edit: after reading dbaupps answer and doing some addition with ref_to_x and *ref_to_x things got a bit clearer; you cannot add an integer to ref_to_x because it's a reference. I guess I got confused because there is no indication of a reference when you print one.

解决方案

ref creates a pointer into the piece of memory that is being matched on, in this case, ref_to_x is pointing directly to the memory that stores point.x, it is the same as writing let ref_to_x = &point.x in this case.

The pattern is extremely important, as it allows one to reach deep inside complicated data-structures without disturbing the ownership hierarchy. For example, if one has val: &Option<String>, writing

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

is not legal, it gives an error like:

<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) => {}
                      ^

It is not legal to take ownership (move) out of a borrowed value, because that would possibly damage the thing from which the value was borrowed (violating its invariants, causing data to disappear unexpectedly, etc.).

So, one can instead use a reference to just point in the memory with a borrowing & reference.


There's a slight subtlety here because (a) point isn't borrowed, so it is OK to move out of point (which consumes ownership of point too, meaning it can't be used later unless reinitialised), and (b) the type int is Copy, so doesn't move ownership when used by value. This is why using myx instead works fine. If the type of x was, say, String (which isn't Copy) and point was borrowed, then the ref will be necessary.

这篇关于Rust 示例:参考模式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆