Table of Contents

Structs

What is a struct?

So far, you have used individual variables to store data: a name here, an age there, a score somewhere else. But what if you want to group related data together?

A struct (short for "structure") lets you create your own data type by grouping variables together. Think of it like a form: a "Person" form has fields for name, age, and city — and every person you create fills in those same fields.

Defining a struct

struct Person {
    name: String,
    age: int,
    city: String
}

This defines a new type called Person with three fields. No data is created yet — this is just the template.

Creating an instance

To create an actual Person, fill in the fields:

struct Person {
    name: String,
    age: int,
    city: String
}

fn main() {
    let alice: Person = Person { name: "Alice", age: 30, city: "Berlin" }
    print(alice.name)    // Alice
    print(alice.age)     // 30
    print(alice.city)    // Berlin
}

The dot notation (alice.name) accesses a field of the struct.

Modifying fields

Use var to create a mutable struct, then modify its fields:

struct Counter {
    value: int
}

fn main() {
    var c: Counter = Counter { value: 0 }
    print(c.value)    // 0

    c.value = c.value + 1
    c.value = c.value + 1
    print(c.value)    // 2
}

Structs as function parameters

You can pass structs to functions:

struct Rectangle {
    width: int,
    height: int
}

fn area(r: Rectangle) -> int {
    return r.width * r.height
}

fn perimeter(r: Rectangle) -> int {
    return 2 * (r.width + r.height)
}

fn main() {
    let rect: Rectangle = Rectangle { width: 10, height: 5 }
    print(area(rect))        // 50
    print(perimeter(rect))   // 30
}

Structs as return values

Functions can also return structs:

struct Point {
    x: int,
    y: int
}

fn make_point(x: int, y: int) -> Point {
    return Point { x: x, y: y }
}

fn add_points(a: Point, b: Point) -> Point {
    return Point { x: a.x + b.x, y: a.y + b.y }
}

fn main() {
    let p1: Point = make_point(3, 4)
    let p2: Point = make_point(1, 2)
    let p3: Point = add_points(p1, p2)

    print(p3.x)    // 4
    print(p3.y)    // 6
}

Why use structs?

Without structs, a function that describes a person might look like this:

fn describe(name: String, age: int, city: String) {
    print(name + " is " + int_to_string(age) + " from " + city)
}

With three parameters, it is manageable. But what if a person has 10 fields? The function signature becomes unreadable. Structs solve this:

struct Person {
    name: String,
    age: int,
    city: String
}

fn describe(p: Person) {
    print(p.name + " is " + int_to_string(p.age) + " from " + p.city)
}

fn main() {
    let alice: Person = Person { name: "Alice", age: 30, city: "Berlin" }
    describe(alice)    // Alice is 30 from Berlin
}

One parameter instead of three. And if you add more fields later, the function signature does not change.

Structs with arrays

You can put structs in arrays:

struct Student {
    name: String,
    grade: int
}

fn best_student(students: Array) -> String {
    var best_name: String = ""
    var best_grade: int = 0
    var i: int = 0
    while i < students.length() {
        let s: Student = students[i]
        if s.grade > best_grade {
            best_grade = s.grade
            best_name = s.name
        }
        i += 1
    }
    return best_name
}

fn main() {
    let students: Array = [
        Student { name: "Alice", grade: 92 },
        Student { name: "Bob", grade: 88 },
        Student { name: "Charlie", grade: 97 }
    ]

    print(best_student(students))    // Charlie
}

Practical example: a simple inventory

struct Item {
    name: String,
    quantity: int,
    price: int
}

fn total_value(items: Array) -> int {
    var total: int = 0
    var i: int = 0
    while i < items.length() {
        let item: Item = items[i]
        total += item.quantity * item.price
        i += 1
    }
    return total
}

fn main() {
    let inventory: Array = [
        Item { name: "Apple", quantity: 50, price: 2 },
        Item { name: "Bread", quantity: 20, price: 3 },
        Item { name: "Milk", quantity: 30, price: 4 }
    ]

    print(total_value(inventory))    // 50*2 + 20*3 + 30*4 = 280
}

Exercises

  1. Define a Book struct with title: String, author: String, and pages: int. Create 3 books and print their titles.
  1. Write a function longest_book(books: Array) -> String that returns the title of the book with the most pages.
  1. Define a Circle struct with radius: int. Write functions circle_area(c: Circle) -> int and circle_circumference(c: Circle) -> int that compute approximate values (use 3 as an approximation for pi).
  1. Define a BankAccount struct with owner: String and balance: int. Write functions deposit(account: BankAccount, amount: int) -> BankAccount and withdraw(account: BankAccount, amount: int) -> BankAccount that return new accounts with updated balances.
  1. Create an array of 5 Point structs. Write a function that finds the point closest to the origin (0, 0). Use distance squared (xx + yy) to avoid needing square roots.

Summary

Next chapter: Your first project →

← Previous: Maps Next: Your first project →