References to Structs

#1
struct Rectangle
{
    width: i32,
    height: i32,
}

impl Rectangle
{
    fn area(&self) -> i32
    {
        self.width * self.height
    }

    fn can_hold(&self, other: &Rectangle) -> bool // &Rectangle confuses me
    {
        self.width > other.width && self.height > other.height
    }
}

fn main()
{
    let rect1 = Rectangle {width: 30, height: 50};
    let rect2 = Rectangle {width: 10, height: 40};
    let rect3 = Rectangle {width: 60, height: 45};

    println!("Can rect1 hold rect2? {}", rect1.can_hold(&rect2));
    println!("Can rect1 hold rect3? {}", rect1.can_hold(&rect3));
}

fn can_hold(&self, other: &Rectangle) -> bool This line kinda confuses me.

So in the main function, I understand that in this line println!("Can rect1 hold rect2? {}", rect1.can_hold(&rect2)); you are passing a reference of the rect2 struct. But in this associated function fn can_hold(&self, other: &Rectangle) -> bool, is other: &Rectangle telling the compiler that the other variable is a &Rectangle type? And the &self is telling the compiler that use the contents of what is stored in rect1?

#2

other: &Rectangle is telling the compiler the argument is a reference to a rectangle. &self or self as the first argument refers to the object the method is called on, similar to this in other languages. &self means a reference, self means the method consumes the object.

You could have rewritten

fn can_hold(&self, other: &Rectangle) -> bool {
    self.width > other.width && self.height > other.height
}

rect1.can_hold(&rect2);

as

fn can_hold(first: &Rectangle, other: &Rectangle) -> bool {
    first.width > other.width && first.height > other.height
}

Rectangle::can_hold(&rect1, &rect2);
#3

Note that if you do the rewrite, you lose method call syntax.

#4

Another thing to keep in mind is that self and &self are syntactic sugar:

fn foo(&self)

is equivalent to

fn foo(self: &Self)

or more intuitively

impl Bar {
    fn foo(self: &Bar);
}

and therefore you could call this like:

let a_bar = /**/;
let b_bar = /**/;
a_bar.foo(&b_bar);
//or
Bar::foo(&a_bar, &b_bar);

because methods (as in functions that take some kind of self parameter) are really just static functions with a layer of “call sugar” on top in a sense.