Rust 示例:参考模式 [英] Rust by example: The ref pattern
问题描述
我在理解 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
,原始point
的x
值.>
但我不明白 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)类型 int
是 Copy
,所以在使用时不会移动所有权按价值.这就是为什么使用 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屋!