Structs
Model related data with named fields and pass structured values into functions.
Core concepts
struct, fields, struct literals, field access
How the learner should approach this project
Do not paste the complete program immediately. Create the file, type the first step, run vpp check, and then run the program when a complete entry point exists. Read the explanation before looking at the snippet. After each step, predict what the new code should do. This turns the page into a lesson rather than a code dump.
Step 1: Define Point
A struct groups related values into one named type. Point contains two integer fields. The compiler checks that every constructed Point supplies compatible values.
After typing the snippet, identify the new names introduced by the step. Ask what each name represents, what type the compiler should infer or check, and what value should exist after the code runs.
struct Point {
x: int
y: int
}Step 2: Define Rectangle
Rectangle is another product type. Its fields represent dimensions, and the field names make the meaning of each integer explicit.
Before moving forward, explain how this step connects to the previous one. In particular, identify which values cross a function boundary, which values change, and which values are guaranteed by the type system.
struct Rectangle {
width: int
height: int
}Step 3: Pass a struct to a function
A function can accept a struct as one parameter. Field access uses dot notation, so rect.width and rect.height read the named fields.
Before moving forward, explain how this step connects to the previous one. In particular, identify which values cross a function boundary, which values change, and which values are guaranteed by the type system.
fn area(rect: Rectangle) -> int {
return rect.width * rect.height
}Step 4: Construct values and use fields
Struct literals use the type name followed by field assignments. Local type inference means p and box do not need explicit local type annotations.
Before moving forward, explain how this step connects to the previous one. In particular, identify which values cross a function boundary, which values change, and which values are guaranteed by the type system.
fn main() -> int {
let p = Point { x: 3, y: 4 }
print(p.x)
print(p.y)
let box = Rectangle { width: 10, height: 5 }
print(area(box))
return 0
}Complete source
struct Point {
x: int
y: int
}
struct Rectangle {
width: int
height: int
}
fn area(rect: Rectangle) -> int {
return rect.width * rect.height
}
fn main() -> int {
let p = Point { x: 3, y: 4 }
print(p.x)
print(p.y)
let box = Rectangle { width: 10, height: 5 }
print(area(box))
return 0
}Expected behavior
The complete program should produce the following output when run with the command shown below. Exact formatting should follow the current V++ runtime.
3 4 50
Run the project
vpp run projects/06-structs/main.vppWhat the learner should understand after this project
Structs model data with named fields. They make function parameters easier to understand because one typed value can carry several related fields.
Common mistakes to teach
- Using a field name that is not defined
- Supplying a value with the wrong field type
- Forgetting that the function parameter is a whole struct
Practice extension
Create a Student struct with name and age. Write a function that prints the student's name.
A strong learner should be able to explain the program without looking at the code, rebuild the core idea from memory, and make the practice change without copying a solution.
Full program
struct Point {
x: int
y: int
}
struct Rectangle {
width: int
height: int
}
fn area(rect: Rectangle) -> int {
return rect.width * rect.height
}
fn main() -> int {
let p = Point { x: 3, y: 4 }
print(p.x)
print(p.y)
let box = Rectangle { width: 10, height: 5 }
print(area(box))
return 0
}