I try to understand the borrow mechanism and references in Rust, and for this reason I created the following small example:
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])
}
So, the above code works, but my confusion comes when calling the double
method. As you can see it is defined as fn double(&self) -> Element
, so it basically takes an immutable reference. Now in the main, I create a new Element
variable called a
, and then call double
method on it twice. First time I just do a.double()
, second time (&a).double()
. Both of them seem to work correctly, but I do not understand why the first call a.double()
is a valid and compiler doesn't complain about it. Since a
is of type Element
, not of type &Element
, and clearly the double
method asks for &Element
, so about a reference. Same thing also happens with the mut_double
method. Why do I not have to specify (&a)
or (&mut a)
when calling the double
and mut_double
methods, respectively? What is happening under the hood with Rust?