我尝试理解Rust中的借用机制和引用,因此我创建了以下小例子:
extern crate core;
use core::fmt::Debug;
#[derive(Copy, Clone)]
pub struct Element(pub (crate) [u8; 5]);
impl Debug for Element {
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
write!(f, "Element({:?})", &self.0[..])
}
}
impl Element {
fn one() -> Element {
Element([1, 1, 1, 1, 1])
}
fn double(&self) -> Element {
let mut result = *self;
for i in 0..5 { result.0[i] = 2*result.0[i]; }
result
}
fn mut_double(&mut self) -> Element {
for i in 0..5 { self.0[i] = 2*self.0[i]; }
*self
}
}
fn main() {
let mut a = Element::one();
println!("a = {:?}", a); // a = Element([1, 1, 1, 1, 1])
a = a.double();
println!("a = {:?}", a); // a = Element([2, 2, 2, 2, 2])
a = (&a).double();
println!("a = {:?}", a); // a = Element([4, 4, 4, 4, 4])
a = a.mut_double();
println!("a = {:?}", a); // a = Element([8, 8, 8, 8, 8])
a = (&mut a).mut_double();
println!("a = {:?}", a); // a = Element([16, 16, 16, 16, 16])
}
所以,上面的代码可行,但是在调用double
方法时出现了混乱。如您所见,它被定义为fn double(&self) -> Element
,因此它基本上采用不可变引用。现在主要是,我创建了一个名为Element
的新a
变量,然后在其上调用double
方法两次。我第一次a.double()
,第二次(&a).double()
。它们似乎都正常工作,但我不明白为什么第一个调用a.double()
是有效的,编译器不会抱怨它。由于a
属于Element
类型,而不属于&Element
类型,并且double
方法明确要求&Element
,因此有关参考。 mut_double
方法也会发生同样的事情。为什么在分别调用(&a)
和(&mut a)
方法时,我不必指定double
或mut_double
?在Rust的引擎盖下发生了什么?
答案 0 :(得分:4)
简短:语言就是这样,因为它更方便。
长(extract from the book,强调是我的):
->
运营商在哪里?在像C ++这样的语言中,两个不同的运算符用于调用方法: 如果您直接在对象上调用方法,并使用
.
if,则使用->
你在指向对象的指针上调用方法,需要解除引用 指针首先。换句话说,如果object
是指针,object->something()
与(*object).something()
类似。Rust没有
->
运算符的等价物;相反,Rust有一个 称为自动引用和解除引用的功能。调用方法是 Rust中为数不多的有这种行为的地方之一。以下是它的工作原理:当您使用
object.something()
, Rust调用方法时 自动添加&
,&mut
或*
,以便object
与 方法。换句话说,以下是相同的:p1.distance(&p2); (&p1).distance(&p2);
第一个看起来更干净。此自动引用行为有效 因为方法有一个明确的接收者 -
self
的类型。鉴于接收器 和方法的名称,Rust可以明确地确定方法是否 阅读(&self
),变异(&mut self
)或消费(self
)。这个事实 Rust为方法接收器隐含的借用是制作的重要部分 在实践中所有权符合人体工程学。