Rust 中符号“&”和星号“*”的含义
Meaning of the ampersand '&' and star '*' symbols in Rust
尽管仔细阅读了文档,但我对 Rust 中 &
和 *
符号的含义,以及更普遍的 Rust 引用到底是什么感到困惑。
在这个例子中,它似乎类似于C++引用(即使用时自动解引用的地址):
fn main() {
let c: i32 = 5;
let rc = &c;
let next = rc + 1;
println!("{}", next); // 6
}
但是,以下代码的工作原理完全相同:
fn main() {
let c: i32 = 5;
let rc = &c;
let next = *rc + 1;
println!("{}", next); // 6
}
使用 *
取消引用引用在 C++ 中是不正确的。所以我想了解为什么这在 Rust 中是正确的。
到目前为止,我的理解是,在 Rust 引用前面插入 *
会取消引用它,但是 *
无论如何都是隐式插入的,因此您不需要添加它(虽然在 C++ 中,它是隐式插入的,如果你插入它,你会得到一个编译错误。
但是,像这样的东西不能编译:
fn main() {
let mut c: i32 = 5;
let mut next: i32 = 0;
{
let rc = &mut c;
next = rc + 1;
}
println!("{}", next);
}
error[E0369]: binary operation `+` cannot be applied to type `&mut i32`
--> src/main.rs:6:16
|
6 | next = rc + 1;
| ^^^^^^
|
= note: this is a reference to a type that `+` can be applied to; you need to dereference this variable once for this operation to work
= note: an implementation of `std::ops::Add` might be missing for `&mut i32`
但这行得通:
fn main() {
let mut c: i32 = 5;
let mut next: i32 = 0;
{
let rc = &mut c;
next = *rc + 1;
}
println!("{}", next); // 6
}
似乎隐式取消引用(la C++)对于不可变引用是正确的,但对于可变引用则不然。这是为什么?
Using * to dereference a reference wouldn't be correct in C++. So I'd like to understand why this is correct in Rust.
C++ 中的引用与 Rust 中的引用不同。 Rust 的引用更接近(在用法上,而不是在语义上)C++ 的指针。关于内存表示,Rust 的引用通常只是一个指针,而 C++ 的引用应该是同一对象的替代名称(因此没有内存表示)。
C++ 指针和 Rust 引用之间的区别在于 Rust 的引用永远不会 NULL
、永远不会未初始化并且永远不会悬挂。
为以下对和所有其他数字基元实现了 Add
特性(请参阅文档页面底部):
&i32
+ i32
i32
+ &i32
&i32
+ &i32
这只是 std-lib 开发人员为了方便而实现的。编译器可以计算出 &mut i32
可以在任何可以使用 &i32
的地方使用,但这对泛型不起作用(还?),因此 std-lib 开发人员还需要实现Add
以下组合的特征(以及所有基元的特征):
&mut i32
+ i32
i32
+ &mut i32
&mut i32
+ &mut i32
&mut i32
+ &i32
&i32
+ &mut i32
如您所见,这可能会变得一发不可收拾。我相信这会在未来消失。在此之前,请注意以 &mut i32
结尾并尝试在数学表达式中使用它的情况相当罕见。
来自 std::ops::Add
的文档:
impl<'a, 'b> Add<&'a i32> for &'b i32
impl<'a> Add<&'a i32> for i32
impl<'a> Add<i32> for &'a i32
impl Add<i32> for i32
数字的二元 + 运算符似乎是针对操作数的共享(但不是可变的)引用和操作数的拥有版本的组合实现的。它与自动取消引用无关。
此答案适用于那些寻找基础知识的人(例如来自 Google)。
来自 Rust 书的 References and Borrowing:
fn main() {
let s1 = String::from("hello");
let len = calculate_length(&s1);
println!("The length of '{}' is {}.", s1, len);
}
fn calculate_length(s: &String) -> usize {
s.len()
}
These ampersands represent references, and they allow you to refer to some value without taking ownership of it [i.e. borrowing].
The opposite of referencing by using &
is dereferencing, which is accomplished with the dereference operator, *
.
还有一个基本示例:
let x = 5;
let y = &x; //set y to a reference to x
assert_eq!(5, x);
assert_eq!(5, *y); // dereference y
如果我们尝试编写 assert_eq!(5, y);
,我们会得到一个编译错误 can't compare `{integer}` with `&{integer}`
。
(您可以在 Smart Pointers chapter 中阅读更多内容。)
来自 Method Syntax:
Rust has a feature called automatic referencing and dereferencing. Calling methods is one of the few places in Rust that has this behavior.
Here’s how it works: when you call a method with object.something()
, Rust automatically adds in &
, &mut
, or *
so object matches the signature of the method. In other words, the following are the same:
p1.distance(&p2);
(&p1).distance(&p2);
尽管仔细阅读了文档,但我对 Rust 中 &
和 *
符号的含义,以及更普遍的 Rust 引用到底是什么感到困惑。
在这个例子中,它似乎类似于C++引用(即使用时自动解引用的地址):
fn main() {
let c: i32 = 5;
let rc = &c;
let next = rc + 1;
println!("{}", next); // 6
}
但是,以下代码的工作原理完全相同:
fn main() {
let c: i32 = 5;
let rc = &c;
let next = *rc + 1;
println!("{}", next); // 6
}
使用 *
取消引用引用在 C++ 中是不正确的。所以我想了解为什么这在 Rust 中是正确的。
到目前为止,我的理解是,在 Rust 引用前面插入 *
会取消引用它,但是 *
无论如何都是隐式插入的,因此您不需要添加它(虽然在 C++ 中,它是隐式插入的,如果你插入它,你会得到一个编译错误。
但是,像这样的东西不能编译:
fn main() {
let mut c: i32 = 5;
let mut next: i32 = 0;
{
let rc = &mut c;
next = rc + 1;
}
println!("{}", next);
}
error[E0369]: binary operation `+` cannot be applied to type `&mut i32`
--> src/main.rs:6:16
|
6 | next = rc + 1;
| ^^^^^^
|
= note: this is a reference to a type that `+` can be applied to; you need to dereference this variable once for this operation to work
= note: an implementation of `std::ops::Add` might be missing for `&mut i32`
但这行得通:
fn main() {
let mut c: i32 = 5;
let mut next: i32 = 0;
{
let rc = &mut c;
next = *rc + 1;
}
println!("{}", next); // 6
}
似乎隐式取消引用(la C++)对于不可变引用是正确的,但对于可变引用则不然。这是为什么?
Using * to dereference a reference wouldn't be correct in C++. So I'd like to understand why this is correct in Rust.
C++ 中的引用与 Rust 中的引用不同。 Rust 的引用更接近(在用法上,而不是在语义上)C++ 的指针。关于内存表示,Rust 的引用通常只是一个指针,而 C++ 的引用应该是同一对象的替代名称(因此没有内存表示)。
C++ 指针和 Rust 引用之间的区别在于 Rust 的引用永远不会 NULL
、永远不会未初始化并且永远不会悬挂。
为以下对和所有其他数字基元实现了 Add
特性(请参阅文档页面底部):
&i32
+i32
i32
+&i32
&i32
+&i32
这只是 std-lib 开发人员为了方便而实现的。编译器可以计算出 &mut i32
可以在任何可以使用 &i32
的地方使用,但这对泛型不起作用(还?),因此 std-lib 开发人员还需要实现Add
以下组合的特征(以及所有基元的特征):
&mut i32
+i32
i32
+&mut i32
&mut i32
+&mut i32
&mut i32
+&i32
&i32
+&mut i32
如您所见,这可能会变得一发不可收拾。我相信这会在未来消失。在此之前,请注意以 &mut i32
结尾并尝试在数学表达式中使用它的情况相当罕见。
来自 std::ops::Add
的文档:
impl<'a, 'b> Add<&'a i32> for &'b i32
impl<'a> Add<&'a i32> for i32
impl<'a> Add<i32> for &'a i32
impl Add<i32> for i32
数字的二元 + 运算符似乎是针对操作数的共享(但不是可变的)引用和操作数的拥有版本的组合实现的。它与自动取消引用无关。
此答案适用于那些寻找基础知识的人(例如来自 Google)。
来自 Rust 书的 References and Borrowing:
fn main() { let s1 = String::from("hello"); let len = calculate_length(&s1); println!("The length of '{}' is {}.", s1, len); } fn calculate_length(s: &String) -> usize { s.len() }
These ampersands represent references, and they allow you to refer to some value without taking ownership of it [i.e. borrowing].
The opposite of referencing by using
&
is dereferencing, which is accomplished with the dereference operator,*
.
还有一个基本示例:
let x = 5;
let y = &x; //set y to a reference to x
assert_eq!(5, x);
assert_eq!(5, *y); // dereference y
如果我们尝试编写 assert_eq!(5, y);
,我们会得到一个编译错误 can't compare `{integer}` with `&{integer}`
。
(您可以在 Smart Pointers chapter 中阅读更多内容。)
来自 Method Syntax:
Rust has a feature called automatic referencing and dereferencing. Calling methods is one of the few places in Rust that has this behavior.
Here’s how it works: when you call a method with
object.something()
, Rust automatically adds in&
,&mut
, or*
so object matches the signature of the method. In other words, the following are the same:p1.distance(&p2); (&p1).distance(&p2);