Apps Artificial Intelligence CSS DevOps Go JavaScript Laravel Linux MongoDB MySQL PHP Python Rust Svelte Vue

Method Syntax in Rust

2 min read .
Method Syntax in Rust

Rust methods define behavior associated with a type such as a struct or enum. They are usually declared inside an impl block and are called on a value with dot syntax.

What Is a Method in Rust?

A method is a function whose first parameter is some form of self, which represents the value the method is called on. Methods keep behavior close to the type it belongs to and often make APIs easier to read.

Define Methods with impl

struct Circle {
    radius: f64,
}

impl Circle {
    fn area(&self) -> f64 {
        std::f64::consts::PI * self.radius * self.radius
    }

    fn circumference(&self) -> f64 {
        2.0 * std::f64::consts::PI * self.radius
    }
}

fn main() {
    let circle = Circle { radius: 5.0 };

    println!("Area: {:.2}", circle.area());
    println!("Circumference: {:.2}", circle.circumference());
}
  • impl Circle defines behavior for Circle.
  • &self borrows the current instance immutably.
  • Methods are called with dot syntax, such as circle.area().

Understand self, &self, and &mut self

self: consume the value

struct Container {
    items: Vec<i32>,
}

impl Container {
    fn consume(self) -> Vec<i32> {
        self.items
    }
}

fn main() {
    let container = Container { items: vec![1, 2, 3] };
    let items = container.consume();
    println!("{:?}", items);
}

A method taking self by value normally consumes the instance.

&self: read-only borrowing

struct Rectangle {
    width: u32,
    height: u32,
}

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

Use &self when the method only needs to inspect the value.

&mut self: mutable borrowing

struct Counter {
    value: i32,
}

impl Counter {
    fn increment(&mut self) {
        self.value += 1;
    }
}

fn main() {
    let mut counter = Counter { value: 0 };
    counter.increment();
    println!("Counter value: {}", counter.value);
}

Use &mut self when the method needs to modify the instance in place.

Method Chaining

Methods can return self, &self, or &mut self to support fluent call chains:

struct Builder {
    name: String,
    count: u32,
}

impl Builder {
    fn new(name: &str) -> Self {
        Self {
            name: name.to_string(),
            count: 0,
        }
    }

    fn increment(&mut self) -> &mut Self {
        self.count += 1;
        self
    }

    fn set_name(&mut self, name: &str) -> &mut Self {
        self.name = name.to_string();
        self
    }

    fn build(&self) {
        println!("Builder: {}, Count: {}", self.name, self.count);
    }
}

fn main() {
    Builder::new("Initial")
        .increment()
        .increment()
        .set_name("Updated")
        .build();
}

Returning &mut Self is useful for builder-like APIs that mutate one value through a sequence of calls.

Associated Functions

Functions inside an impl block that do not take self are called associated functions:

struct Calculator;

impl Calculator {
    fn add(a: i32, b: i32) -> i32 {
        a + b
    }

    fn new() -> Self {
        Calculator
    }
}

fn main() {
    let _calculator = Calculator::new();
    let sum = Calculator::add(10, 20);
    println!("Sum: {}", sum);
}

Associated functions are called with Type::function() syntax. Constructors named new are a convention rather than a special language feature.

Best Practices

  1. Use &self when a method only reads state.
  2. Use &mut self for in-place mutation.
  3. Take self when consuming the value is part of the API contract.
  4. Use associated functions for constructors and operations that belong to the type but do not require an instance.
  5. Support chaining only when it makes the API clearer rather than merely shorter.
  6. Keep methods focused and choose names that communicate the operation’s effect.

Conclusion

Rust method syntax combines familiar dot notation with explicit ownership choices. Deciding whether a method takes self, &self, or &mut self makes its ownership and mutation behavior visible in the signature, which is a major part of designing clear Rust APIs.

Related Posts

chevron-up