我试图了解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
是type Element
,而不是type &Element
,并且double
方法显然要求&Element
,因此参考。该mut_double
方法也发生同样的事情。为什么不必指定(&a)
或(&mut a)
在调用double
and时mut_double
方法分别?Rust在幕后发生了什么?
简短:语言之所以这样工作,是因为它更加方便。
长(从书中摘录,重点是我的):
->
接线员在哪里?在C ++之类的语言中,使用两种不同的运算符来调用方法:
.
如果您要直接在对象上调用方法,并且->
是在指向对象的指针上调用方法,则需要先取消引用该指针。换句话说,如果object
是指针,object->something()
则类似于(*object).something()
。Rust没有与
->
运算符等效的对象;相反,Rust具有称为自动引用和取消引用的功能。调用方法是Rust少数具有这种行为的地方之一。下面是它如何工作的:当你调用一个方法有
object.something()
,铁锈会自动添加&
,&mut
或*
使object
该方法的签名相匹配。换句话说,以下是相同的:p1.distance(&p2); (&p1).distance(&p2);
第一个看起来更干净。由于方法具有明确的接收方(的类型),因此这种自动引用行为有效
self
。给定方法的接收者和名称,Rust可以明确地确定该方法是读取(&self
),变异(&mut self
)还是使用(self
)。在实践中,Rust使方法接收者隐含借贷这一事实是使所有权符合人体工程学的重要组成部分。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句