Pattern Matching
Use exhaustive matching over enums so every legal state has defined behavior.
Core concepts
exhaustive match, enum patterns, struct wrapping an enum
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 Day
The Day enum lists every day. Because the compiler knows all seven variants, a match can be checked for completeness.
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.
enum Day {
Mon
Tue
Wed
Thu
Fri
Sat
Sun
}Step 2: Wrap Day in a struct
CalendarDay gives the example a named field. This is useful when a larger model eventually contains more information about a date.
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 CalendarDay {
day: Day
}Step 3: Write an exhaustive weekend check
The function returns true for Sat and Sun and false for every weekday. There is no default branch because the compiler can verify that all seven variants are covered explicitly.
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 is_weekend(entry: CalendarDay) -> bool {
match entry.day {
Sat => {
return true
}
Sun => {
return true
}
Mon => {
return false
}
Tue => {
return false
}
Wed => {
return false
}
Thu => {
return false
}
Fri => {
return false
}
}
}Step 4: Test two cases
The main function constructs one weekend value and one weekday value. Calling the same function with both demonstrates that the enum controls behavior without unsafe integer codes.
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 weekend = CalendarDay { day: Sat }
let weekday = CalendarDay { day: Wed }
print(is_weekend(weekend))
print(is_weekend(weekday))
return 0
}Complete source
enum Day {
Mon
Tue
Wed
Thu
Fri
Sat
Sun
}
struct CalendarDay {
day: Day
}
fn is_weekend(entry: CalendarDay) -> bool {
match entry.day {
Sat => {
return true
}
Sun => {
return true
}
Mon => {
return false
}
Tue => {
return false
}
Wed => {
return false
}
Thu => {
return false
}
Fri => {
return false
}
}
}
fn main() -> int {
let weekend = CalendarDay { day: Sat }
let weekday = CalendarDay { day: Wed }
print(is_weekend(weekend))
print(is_weekend(weekday))
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.
true false
Run the project
vpp run projects/09-match/main.vppWhat the learner should understand after this project
Exhaustiveness is a compile time safety property. Adding a new enum variant creates a deliberate reminder to update affected match expressions.
Common mistakes to teach
- Removing a match arm and ignoring the exhaustiveness error
- Confusing the enum value with the struct that contains it
- Returning the wrong boolean for a variant
Practice extension
Intentionally remove one match arm and run vpp check. Study the compiler error, then restore the missing case.
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
enum Day {
Mon
Tue
Wed
Thu
Fri
Sat
Sun
}
struct CalendarDay {
day: Day
}
fn is_weekend(entry: CalendarDay) -> bool {
match entry.day {
Sat => {
return true
}
Sun => {
return true
}
Mon => {
return false
}
Tue => {
return false
}
Wed => {
return false
}
Thu => {
return false
}
Fri => {
return false
}
}
}
fn main() -> int {
let weekend = CalendarDay { day: Sat }
let weekday = CalendarDay { day: Wed }
print(is_weekend(weekend))
print(is_weekend(weekday))
return 0
}