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
,原来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<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) 类型 int
是 Copy
,因此在按值使用时不会移动所有权。这就是为什么使用 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 */
}
},
}
我无法理解 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
,原来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<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) 类型 int
是 Copy
,因此在按值使用时不会移动所有权。这就是为什么使用 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 */
}
},
}