Methods and Impl Blocks

Loading concept...

🦀 Rust Structs: Methods and Impl Blocks

The Restaurant Kitchen Analogy 🍳

Imagine you own a tiny restaurant. You have a recipe card (that’s your struct) with all the ingredients listed. But a recipe card just sitting there doesn’t cook anything!

You need chefs who know how to use that recipe. In Rust, those chefs are called methods, and they live inside a special kitchen called an impl block.


What is an impl Block?

An impl block is like a kitchen attached to your recipe. It’s where you write all the actions (methods) that work with your struct.

struct Pizza {
    topping: String,
    size: u8,
}

impl Pizza {
    // Methods go here!
}

Think of it this way:

  • struct Pizza = The recipe card listing ingredients
  • impl Pizza = The kitchen where chefs cook pizzas

Methods: Actions Your Struct Can Do

A method is a function that belongs to a struct. It can read or change the struct’s data.

The Magic Word: self

Every method gets a special helper called self. It’s like saying “this pizza” or “the pizza we’re working on right now.”

impl Pizza {
    fn describe(&self) {
        println!(
            "A {} inch pizza with {}",
            self.size,
            self.topping
        );
    }
}

Breaking it down:

  • &self = “Let me look at this pizza” (borrow, read-only)
  • self.size = “The size of THIS pizza”
  • self.topping = “The topping on THIS pizza”

Using Your Method

fn main() {
    let my_pizza = Pizza {
        topping: String::from("pepperoni"),
        size: 12,
    };

    my_pizza.describe();
    // Prints: A 12 inch pizza with pepperoni
}

Notice the dot! We call my_pizza.describe() just like calling a friend: “Hey pizza, describe yourself!”


The Three Flavors of self

Think of borrowing a book from a library:

Type Meaning Real-Life Example
&self “I’ll just look” Reading a library book
&mut self “I’ll make notes” Editing your own book
self “I’m taking it” Buying the book (it’s yours now)

Example: All Three in Action

struct Cookie {
    bites_left: u8,
}

impl Cookie {
    // Just looking (read-only)
    fn check(&self) -> u8 {
        self.bites_left
    }

    // Making changes
    fn take_bite(&mut self) {
        if self.bites_left > 0 {
            self.bites_left -= 1;
        }
    }

    // Eating the whole thing!
    fn eat(self) {
        println!("Yum! Cookie is gone!");
        // Cookie is consumed here
    }
}

Associated Functions: The Factory Workers

Sometimes you need a function that makes a struct, not one that uses it.

These are called associated functions. They don’t use self because there’s no struct yet—they’re building one!

impl Pizza {
    // Associated function (no self!)
    fn new(topping: String) -> Pizza {
        Pizza {
            topping,
            size: 10, // Default size
        }
    }
}

Calling Associated Functions

Notice the double colon ::? That’s how you call functions that belong to the type itself, not an instance.

fn main() {
    // Using ::new() to create a pizza
    let cheese_pizza = Pizza::new(
        String::from("cheese")
    );

    // Now we can use methods with .
    cheese_pizza.describe();
}

The difference:

  • Pizza::new() → Calling the factory (makes a pizza)
  • pizza.describe() → Asking a pizza to do something

Quick Comparison

graph TD A["impl Block"] --> B["Methods"] A --> C["Associated Functions"] B --> D["Use self<br/>Call with .dot"] C --> E["No self<br/>Call with ::colons"] D --> F["pizza.describe#40;#41;"] E --> G["Pizza::new#40;#41;"]

The Self Type (Capital S!)

There’s a handy shortcut: Self (with a capital S) means “the type we’re implementing for.”

impl Pizza {
    fn new(topping: String) -> Self {
        Self {
            topping,
            size: 10,
        }
    }
}

Self = Pizza here. It’s like saying “make one of me!”

Why use it?

  • Less typing
  • If you rename the struct, the code still works
  • Makes copy-pasting easier

Multiple impl Blocks

You can split methods into separate blocks! This is useful for organization.

struct Robot {
    name: String,
    battery: u8,
}

// Movement methods
impl Robot {
    fn walk(&mut self) {
        self.battery -= 5;
        println!("{} walks!", self.name);
    }
}

// Factory methods
impl Robot {
    fn new(name: String) -> Self {
        Self { name, battery: 100 }
    }
}

Both blocks work together—Rust combines them automatically!


Putting It All Together 🎉

Let’s build a complete example:

struct BankAccount {
    owner: String,
    balance: u32,
}

impl BankAccount {
    // Associated function: create account
    fn new(owner: String) -> Self {
        Self { owner, balance: 0 }
    }

    // Method: check balance (read)
    fn check_balance(&self) -> u32 {
        self.balance
    }

    // Method: deposit (modify)
    fn deposit(&mut self, amount: u32) {
        self.balance += amount;
    }

    // Method: withdraw (modify)
    fn withdraw(&mut self, amount: u32) -> bool {
        if amount <= self.balance {
            self.balance -= amount;
            true
        } else {
            false
        }
    }
}

fn main() {
    // Create with ::
    let mut account = BankAccount::new(
        String::from("Alice")
    );

    // Use methods with .
    account.deposit(100);
    account.withdraw(30);

    println!(
        "Balance: ${}",
        account.check_balance()
    );
    // Prints: Balance: $70
}

Key Takeaways 🔑

Concept What It Means Example
impl block Kitchen for methods impl Pizza { }
Method Action with self fn eat(&self)
Associated function No self, creates things fn new() -> Self
&self Borrow, read-only Looking at data
&mut self Borrow, can modify Changing data
self Take ownership Consuming the struct
Self The type itself Shortcut in impl
. dot Call methods pizza.eat()
:: colons Call associated funcs Pizza::new()

You Did It! 🎊

Now you know how to give your structs superpowers:

  1. Wrap them in impl blocks
  2. Add methods with self for actions
  3. Add associated functions for creating new instances
  4. Use the right self type based on what you need

Go build something awesome! 🚀

Loading story...

Story - Premium Content

Please sign in to view this story and start learning.

Upgrade to Premium to unlock full access to all stories.

Stay Tuned!

Story is coming soon.

Story Preview

Story - Premium Content

Please sign in to view this concept and start learning.

Upgrade to Premium to unlock full access to all content.

Interactive Preview

Interactive - Premium Content

Please sign in to view this concept and start learning.

Upgrade to Premium to unlock full access to all content.

Interactive - Premium Content

Please sign in to view this interactive content and start learning.

Upgrade to Premium to unlock full access to all interactive content.

Stay Tuned!

Interactive content is coming soon.

Cheatsheet Preview

Cheatsheet - Premium Content

Please sign in to view this concept and start learning.

Upgrade to Premium to unlock full access to all content.

Cheatsheet - Premium Content

Please sign in to view this cheatsheet and start learning.

Upgrade to Premium to unlock full access to all cheatsheets.

Stay Tuned!

Cheatsheet is coming soon.

Quiz Preview

Quiz - Premium Content

Please sign in to view this concept and start learning.

Upgrade to Premium to unlock full access to all content.

Quiz - Premium Content

Please sign in to view this quiz and test your knowledge.

Upgrade to Premium to unlock full access to all quizzes.

Stay Tuned!

Quiz is coming soon.

Flashcard Preview

Flashcard - Premium Content

Please sign in to view this concept and start learning.

Upgrade to Premium to unlock full access to all content.

Flashcard - Premium Content

Please sign in to view flashcards and reinforce your learning.

Upgrade to Premium to unlock full access to all flashcards.

Stay Tuned!

Flashcards are coming soon.