Methods in Rust

Rust supports methods defined on struct types.

struct Rect {
    width: i32,
    height: i32,
}

// This `area` method is associated with the `Rect` struct.
impl Rect {
    fn area(&self) -> i32 {
        self.width * self.height
    }

    // Methods can be defined for either borrowed or owned self.
    // Here's an example of a method that takes ownership of self.
    fn perim(self) -> i32 {
        2 * self.width + 2 * self.height
    }
}

fn main() {
    let r = Rect { width: 10, height: 5 };

    // Here we call the 2 methods defined for our struct.
    println!("area: {}", r.area());
    println!("perim: {}", r.perim());

    // In Rust, method calls automatically dereference when calling a method on a reference.
    // You don't need to explicitly dereference.
    let rp = &r;
    println!("area: {}", rp.area());
    
    // Note: We can't call perim() on rp because it takes ownership,
    // and we can't move out of a borrowed context.
    // This line would cause a compilation error:
    // println!("perim: {}", rp.perim());
}

To run the program:

$ rustc methods.rs
$ ./methods
area: 50
perim: 30
area: 50

In Rust, methods are defined within impl blocks. The &self in the area method is similar to this in other languages, but in Rust, you explicitly specify whether you’re borrowing (&self), mutably borrowing (&mut self), or taking ownership (self).

Rust doesn’t require explicit dereferencing when calling methods on references. This is known as “auto-dereferencing” or “deref coercion”.

Note that in this Rust version, we can’t call perim() on a reference because it takes ownership of self. This demonstrates Rust’s ownership system, which prevents use-after-move errors at compile time.

Next, we’ll look at Rust’s mechanism for defining abstract behavior: traits.