Skip to main content
Rust Programming
CHAPTER 12 Beginner

Structs in Rust

Updated: May 18, 2026
5 min read

# CHAPTER 12

Structs in Rust

1. Chapter Introduction

If you are building an Employee Management system, you cannot pass around 5 separate variables (firstname, lastname, email, age, active) every time you want to process an employee. You need to group related data together. In Object-Oriented languages like Java or C++, you use a class. Rust does not have classes. Instead, Rust uses Structs to organize data, and separates the logic (methods) into a distinct block.

2. Learning Objectives

By the end of this chapter, you will be able to:
  • Define and instantiate a standard Struct.
  • Access and modify struct fields.
  • Implement methods using the impl block.
  • Understand the &self parameter in methods.
  • Create Associated Functions (similar to static methods/constructors).

3. Defining and Instantiating a Struct

A struct allows you to name and package multiple related values.

1. Define the Struct

rust
123456
struct User {
    username: String,
    email: String,
    sign_in_count: u64,
    active: bool,
}

2. Instantiate the Struct

rust
123456789101112131415
fn main() {
    // To change values later, the ENTIRE struct must be mut
    let mut user1 = User {
        email: String::from("alice@example.com"),
        username: String::from("alice123"),
        active: true,
        sign_in_count: 1,
    };

    // Access fields using dot notation
    println!("User email: {}", user1.email);

    // Modify a field
    user1.email = String::from("alice_new@example.com");
}

4. Struct Update Syntax

If you want to create a new user based on an existing user but only change the email, you can use the .. syntax.
rust
12345
let user2 = User {
    email: String::from("bob@example.com"),
    username: String::from("bob99"),
    ..user1 // Fills the rest of the fields (active, sign_in_count) from user1
};

5. Adding Methods using the impl Block

Structs hold data, but they don't hold logic. To attach actions to a struct, we use an Implementation block (impl). Inside the impl block, methods must take a reference to self as their first parameter. &self is short for self: &Self, meaning "borrow the struct instance".
rust
1234567891011121314151617181920212223242526
struct Rectangle {
    width: u32,
    height: u32,
}

// Attach methods to Rectangle
impl Rectangle {
    // Method that borrows the instance to read data
    fn area(&self) -> u32 {
        self.width * self.height
    }

    // Method with multiple parameters
    fn can_hold(&self, other: &Rectangle) -> bool {
        self.width > other.width && self.height > other.height
    }
}

fn main() {
    let rect1 = Rectangle { width: 30, height: 50 };
    let rect2 = Rectangle { width: 10, height: 40 };

    // Call methods using dot notation
    println!("The area is {} square pixels.", rect1.area());
    println!("Can rect1 hold rect2? {}", rect1.can_hold(&rect2));
}

6. Associated Functions (Constructors)

You can write functions inside an impl block that do NOT take &self as a parameter. These are called Associated Functions. They are associated with the Struct type itself, not a specific instance. They are commonly used as constructors (like String::new()).
rust
1234567891011121314
impl Rectangle {
    // No &self! This is an associated function.
    fn square(size: u32) -> Rectangle {
        Rectangle {
            width: size,
            height: size,
        }
    }
}

fn main() {
    // Call using double colons :: instead of dot notation!
    let sq = Rectangle::square(20); 
}

7. Tuple Structs

If you want to group data but don't want to bother naming the fields, you can use a Tuple Struct. These are great for giving specific semantic meaning to basic tuples.
rust
123456789
struct Color(i32, i32, i32);
struct Point(i32, i32, i32);

fn main() {
    let black = Color(0, 0, 0);
    let origin = Point(0, 0, 0);
    // black and origin have the same data types inside, 
    // but they are fundamentally different Types and cannot be mixed!
}

8. Common Mistakes

  • Partial Mutability: Trying to make one field of a struct mutable while leaving others immutable. Rust does not allow this. If you declare let mut user = User{...}, the *entire* struct is mutable.
  • Forgetting & on self: If you write fn area(self), you are taking *ownership* of the struct! Calling .area() will instantly destroy the struct after it returns the area. Almost always use &self (borrowing) for methods.

9. Best Practices

  • Use String over &str in Structs (for now): If you try to store a reference &str inside a struct, the compiler will require you to use "Lifetimes" (which we will learn in Chapter 18). For beginners, always use owned String types inside structs.

10. Exercises

  1. 1. Define a Car struct with make (String), model (String), and year (u32).
  1. 2. Write an impl block with an associated function new(make, model, year) that returns a new Car.
  1. 3. Write a method print_details(&self) that prints the car's info.

11. MCQs with Answers

Q1. Does Rust have the class keyword? a) Yes b) No, it uses struct to group data Answer: b) No, it uses struct.

Question 2

How do you access a field inside an instantiated struct?

Question 3

If you want to modify a struct's fields, what must you do?

Question 4

What keyword is used to attach methods to a struct?

Question 5

What must be the very first parameter of a standard struct method?

Question 6

What happens if a method uses self instead of &self?

Q7. What is an Associated Function? a) A function in an impl block that does NOT take &self as a parameter, often used as a constructor b) A function linked to the internet Answer: a) A function that does NOT take &self.
Question 8

How do you call an Associated Function?

Q9. What is a Tuple Struct? a) A struct with named fields b) A named struct where the fields have no names, just data types (e.g., struct Color(i32, i32, i32);) Answer: b) A named struct where the fields have no names.
Question 10

Why is it difficult to put a &str (reference) inside a struct as a beginner?

12. Interview Questions

  • Q: How does Rust separate data representation from behavior (logic) compared to traditional Object-Oriented languages?
  • Q: Differentiate between a Method and an Associated Function inside an impl block.

13. Summary

Structs form the core of Rust's data modeling capability. By defining rigid data layouts and attaching specific, safe behaviors through impl blocks and the &self reference, Rust developers can build highly complex systems that are well-organized and entirely memory safe.

14. Next Chapter Recommendation

Structs are great for grouping different data together, but what if a variable can be one of several different *types* of things? (e.g., An IP address can be either V4 or V6). In Chapter 13: Enums and Pattern Matching, we will explore Rust's powerful Enums, which are arguably the most robust feature in the language.

Finish this Chapter

Save your progress on your learning path and prepare for coding interview challenges.

Discussion

Join the discussion

Log in or create a free account to participate.

Sort: ·