Structs

Methods

A method is a function defined inside an impl block whose first parameter is self (in any receiver form: &self, &mut self, self, or self: Box<Self>) and that is called on an instance using dot-call syntax (instance.method(args)).

Defining and Calling Methods

Inside an impl Type block, the keyword Self (capital S) is an alias for the type the impl block is written for, and self (lowercase s) is shorthand for self: Self, &self for self: &Self, and &mut self for self: &mut Self:

#[derive(Debug)]
struct Circle {
    radius: f64,
}

impl Circle {
    // Read-only method (`&self` borrows the instance immutably)
    fn area(&self) -> f64 {
        std::f64::consts::PI * self.radius * self.radius
    }

    // Mutating method (`&mut self` borrows the instance mutably)
    fn scale(&mut self, factor: f64) {
        self.radius *= factor;
    }

    // Method with additional parameters
    fn can_contain(&self, other: &Self) -> bool {
        self.radius > other.radius
    }
}

fn main() {
    let mut c1 = Circle { radius: 3.0 };
    let c2 = Circle { radius: 5.0 };

    println!("Initial c1 area: {:.2}", c1.area());
    println!("Can c1 contain c2? {}", c1.can_contain(&c2));

    c1.scale(2.0);
    println!("Scaled c1 ({:?}) area: {:.2}", c1, c1.area());
    println!("Can c1 contain c2 now? {}", c1.can_contain(&c2));
}
Initial c1 area: 28.27
Can c1 contain c2? false
Scaled c1 (Circle { radius: 6.0 }) area: 113.10
Can c1 contain c2 now? true

Automatic Referencing and Dereferencing in Method Calls

Unlike C and C++ (which distinguish obj.method() from ptr->method()), Rust's . method-call operator automatically inserts &, &mut, or * so the receiver matches the method's self signature:

Receiver Resolution for `value.method()`:

  1. Exact match `T`           ──> calls `fn method(self)`
  2. Auto-borrow `&T` / `&mut` ──> `c1.area()` becomes `Circle::area(&c1)`
                                   `c1.scale(2.0)` becomes `Circle::scale(&mut c1, 2.0)`
  3. Deref chain `*T`          ──> if `b: Box<Circle>`, `b.area()` dereferences `Box<Circle>`
                                   to `Circle` and then auto-borrows `&Circle`
Expression Written Method Receiver Signature Desugared Function Call
c1.area() fn area(&self) Circle::area(&c1)
(&c1).area() fn area(&self) Circle::area(&c1)
c1.scale(2.0) fn scale(&mut self, f64) Circle::scale(&mut c1, 2.0)
boxed_c1.area() fn area(&self) Circle::area(&*boxed_c1)

Methods with the Same Name as a Field (Getters)

Rust allows a method to share the exact same name as one of the struct's fields. The compiler distinguishes the two by whether parentheses follow the name:

  • instance.field (no parentheses) accesses the field.
  • instance.field() (with parentheses) invokes the method.

This convention is widely used to expose read-only getters for private fields without a get_ prefix:

pub struct UserSession {
    token: String, // Private field
}

impl UserSession {
    pub fn new(token: String) -> Self {
        Self { token }
    }

    // Getter method with the same name as the private `token` field:
    pub fn token(&self) -> &str {
        &self.token
    }
}

fn main() {
    let session = UserSession::new(String::from("tok_live_98a7f"));
    println!("Active token: {}", session.token());
}
Active token: tok_live_98a7f

Universal Function Call Syntax (UFCS) for Methods

Because every method is an associated function whose first parameter is self, you can also call any method using path syntax (Type::method(receiver, args)). This is useful when passing a method as a function pointer (Iterator::map) or disambiguating between two traits that define a method with the same name:

struct Label(String);

impl Label {
    fn len(&self) -> usize {
        self.0.len()
    }
}

fn main() {
    let item = Label(String::from("rust-2024"));

    // Dot-call syntax vs. explicit path syntax:
    assert_eq!(item.len(), Label::len(&item));

    let labels = [Label(String::from("a")), Label(String::from("abc"))];
    let lengths: Vec<usize> = labels.iter().map(Label::len).collect();
    println!("Lengths: {lengths:?}");
}
Lengths: [1, 3]