The receiver can be &self to read, &mut self to change the instance, or self to take ownership of it. These are the borrowing and moving rules from the previous article applied to a method’s first parameter in source.

struct Counter {
    value: u32,
}
 
impl Counter {
    fn current(&self) -> u32 {
        self.value
    }
 
    fn add(&mut self, amount: u32) {
        self.value += amount;
    }
 
    fn into_value(self) -> u32 {
        self.value
    }
}
 
fn main() {
    let mut counter = Counter { value: 10 };
 
    println!("Before: {}", counter.current());
    counter.add(5);
    let final_value = counter.into_value();
    println!("After: {final_value}");
}

current only reads the counter. add changes it, so the binding in main must be mutable. into_value consumes the counter and returns its stored value. Try calling counter.current() after into_value(); the compiler rejects it because counter was moved into that method.

This example is about choosing a receiver for a method. The underlying read, mutable borrow, and move behavior is the same behavior we already studied with ordinary functions.