尽管仔细阅读了文档,但我对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 ++)对于不可变引用是正确的,但对于可变引用则不行。这是为什么?
答案 0 :(得分:16)
在C ++中使用*来取消引用引用是不正确的。所以我想理解为什么这在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
并尝试在数学表达式中使用它。
答案 1 :(得分:3)
来自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
似乎数字的二元+运算符是针对操作数的共享(但不是可变的)引用和操作数的拥有版本的组合实现的。它与自动解除引用无关。
答案 2 :(得分:3)
这个答案适合那些寻找基础知识的人(例如来自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() }
这些&符号是引用,它们允许您在不取得其所有权的情况下引用某些值[即借贷]。
与使用
&
引用相反的是解除引用,这是通过取消引用运算符*
完成的。
一个基本的例子:
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中阅读更多内容。)
Rust有一项名为自动引用和解除引用的功能。调用方法是Rust中为数不多的具有此行为的地方之一。
以下是它的工作原理:当您使用
object.something()
调用方法时,Rust会自动添加&
,&mut
或*
,因此对象与方法的签名匹配。换句话说,以下是相同的:p1.distance(&p2); (&p1).distance(&p2);