Rust Methods
Methods are functions that belong to a type and are called on a value of that type. A struct holds data, and actions like area() and inc() live in an impl block, separate from the struct.
Without methods, every call passes the value
Plain functions take the rectangle as an input on every call:
fn main() {
struct Rect { width: u32, height: u32 }
fn area(rect: &Rect) -> u32 { rect.width * rect.height }
fn perimeter(rect: &Rect) -> u32 { 2 * (rect.width + rect.height) }
let rect = Rect { width: 30, height: 50 };
println!("{} and {}", area(&rect), perimeter(&rect));
}Add behaviour with impl
An impl block adds functions to a type. A method is a function in the block whose first input is self. &self means the method only reads the value:
struct Rectangle { width: u32, height: u32 }
impl Rectangle {
fn area(&self) -> u32 { self.width * self.height }
}
let rect = Rectangle { width: 30, height: 50 };
println!("area = {}", rect.area());&mut self changes the value
drink takes &mut self, so it may change the value. The sip after self is an ordinary extra input, like any function input:
struct Bottle { ml: u32 }
impl Bottle { fn drink(&mut self, sip: u32) { self.ml -= sip; } }
let mut b = Bottle { ml: 500 };
b.drink(120);
println!("left = {}", b.ml);self uses the value up
With no & at all, the method takes the value itself and uses it up:
struct Ticket { seat: u32 }
impl Ticket { fn scan(self) -> String { format!("seat {} scanned", self.seat) } }
let t = Ticket { seat: 12 };
println!("{}", t.scan());
// println!("{}", t.seat); // error: scan used t upNo self: an associated function
A function in the block with no self is an associated function — call it on the type itself, like String::from. Inside the block, Self is a short name for the type itself:
struct Counter { value: i32 }
impl Counter {
fn new() -> Self { Counter { value: 0 } }
}
let c = Counter::new();
println!("fresh = {}", c.value);A method can share a field's name
The brackets make the difference: sq.side reads the field, and sq.side() calls the method. Rust never builds such getter methods automatically:
struct Square { side: u32 }
impl Square {
fn side(&self) -> u32 { self.side }
}
let sq = Square { side: 5 };
println!("field = {} method = {}", sq.side, sq.side());Calls can chain
When a method returns a value that has methods of its own, calls chain. Read a chain from left to right:
let text = " hello ";
println!("trimmed len = {}", text.trim().len());Example
struct Counter { value: i32 }
impl Counter {
fn new() -> Self { Counter { value: 0 } }
fn inc(&mut self) { self.value += 1; }
fn get(&self) -> i32 { self.value }
}
fn main() {
let mut c = Counter::new();
c.inc(); c.inc();
println!("count = {}", c.get());
}Key points
- A type may have more than one impl block — all the methods still belong to the same type
- A receiver may name a fuller self type.
- fn finish(self: Box<Self>) can only be called on a value that sits in a Box.
- The call uses the box up.
In this example, Counter is a struct with one field, value. The impl block adds three functions. new has no self, so it is an associated function. It is called as Counter::new(). It builds a counter at 0. inc takes &mut self and adds 1 to value. get takes &self and only reads. main creates a mut counter, calls inc twice, and prints get(): 2. Notice the receivers tell you the rules at a glance: &self reads, &mut self writes.
Note
Calling rect.area() works whether rect is a value or a reference.
Rust adds the & or &mut automatically, a kindness called auto-referencing.
Try it Yourself
Edit the code, then press Run.
Running is simulated · Rust Playground
Exercise
What does it mean when a method takes self by value (no &)?