Background
Rust borrows the concept of methods from object-oriented languages, but implements them differently: instead of the familiar this or self, methods explicitly take a self parameter. Associated functions appeared as an alternative to static methods in other programming languages—they are tied to a type but not to a specific value.
The Problem
People often confuse methods, associated functions, and free functions. It is not clear when to use a method with self and when to use an associated function without self. There are questions of visibility, auto-dereferencing, and ownership transfer.
The Solution
Methods in Rust are declared with the first parameter being self/ &self/ &mut self inside an impl block (usually for struct or enum). They are called on an instance: object.method(). Associated functions (e.g., new, from) are also declared inside impl but without the first parameter self and are invoked using the double colon: Type::function().
Example code:
struct Point { x: f64, y: f64, } impl Point { // Associated function (constructor) fn new(x: f64, y: f64) -> Self { Self { x, y } } // Method: requires self fn distance_from_origin(&self) -> f64 { (self.x.powi(2) + self.y.powi(2)).sqrt() } } let p = Point::new(3.0, 4.0); printf!("{}", p.distance_from_origin()); // 5.0
Key features:
::Can associated functions be called through an instance (via dot notation)?
This is possible (e.g., p.new(1.0, 2.0)), but highly discouraged: it is misleading because an associated function does not have access to the current object, and the instance is passed while being ignored. It is better to use the syntax Type::func().
Example code:
let p = Point::new(1.0, 2.0); let q = p.new(0.0, 0.0); // Works, but not a best practice!
Can methods be asynchronous?
Yes. Methods can be declared with the async keyword just like free functions:
impl Foo { async fn do_async(&self) { // ... } }
Can both methods and associated functions be declared in the same impl block?
Yes—any combinations are allowed. It is also possible to declare multiple impl blocks for a single type.
A beginner declared the new function outside of impl and tried to use it as a constructor, then accidentally called it through an instance: p.new(1.0, 2.0).
Pros:
Works quickly (the compiler allows it).
Cons:
Code is unreadable, hard to maintain, difficult to use methods with correct self ownership.
All methods and associated functions are strictly declared inside impl, using correct calling syntaxes (Type::new() for constructors, obj.method() for actions).
Pros:
High readability, adherence to best practices.
Cons:
Requires knowledge of Rust idioms and attention to syntax.