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
- Define a
Bookstruct withtitle: String,author: String, andpages: int. Create 3 books and print their titles.
- Write a function
longest_book(books: Array) -> Stringthat returns the title of the book with the most pages.
- Define a
Circlestruct withradius: int. Write functionscircle_area(c: Circle) -> intandcircle_circumference(c: Circle) -> intthat compute approximate values (use 3 as an approximation for pi).
- Define a
BankAccountstruct withowner: Stringandbalance: int. Write functionsdeposit(account: BankAccount, amount: int) -> BankAccountandwithdraw(account: BankAccount, amount: int) -> BankAccountthat return new accounts with updated balances.
- Create an array of 5
Pointstructs. Write a function that finds the point closest to the origin (0, 0). Use distance squared (xx + yy) to avoid needing square roots.
Summary
struct Name { field: Type, ... }defines a new data type.Name { field: value, ... }creates an instance.- Access fields with dot notation:
instance.field - Structs can be passed to functions and returned from functions.
- Use structs to group related data together.
- Structs + arrays let you work with collections of complex data.
Next chapter: Your first project →