Structs, Enums, and Pattern Matching
Design values that express the meaning of your data.
5.1 Values with fields
Use struct to group values together. Access fields with ..
fn absolute(x: i64): i64 {
if x < 0 { 0 - x } else { x }
}
struct Point { x: i64, y: i64 }
fn manhattan(p: Point): i64 {
absolute(p.x) + absolute(p.y)
}
let origin := Point { x: 0, y: 0 }
let delta := Point { x: 3, y: 4 }
perform show("distance", manhattan(delta))
// Read the fields of a point to compute its Manhattan distance.
・ absolute ・ manhattan distance = 7
distance = 7
When splitting a program into files, define or import the functions each file needs to use (Chapter 12).
5.2 Represent alternatives
An enum represents the possible shapes of a value with a finite set of constructors. The standard Option(A) distinguishes an absent value from a present one.
fn unwrap_or(x: Option(i64), fallback: i64): i64 {
match x {
None => fallback
Some(value) => value
}
}
let a := unwrap_or(Some(12), 0)
let b := unwrap_or(None, 99)
perform show("a", a)
perform show("b", b)
// Handle both the present and absent cases of Option.
・ unwrap_or a = 12 b = 99
a = 12
b = 99
Apply a type as Option(i64), not Option<i64>. This is the same notation used to pass arguments to a function that constructs a type.
5.3 Exhaustive match
enum Light { Red, Yellow, Green }
fn instruction(x: Light): Text {
match x {
Red => "stop"
Yellow => "caution"
Green => "go"
}
}
perform show("light", instruction(Yellow))
// Give an instruction for every traffic-light state.
・ instruction light = "caution"
light = "caution"
Writing an arm for every alternative makes it clear what must change when a new constructor is added to Light. You can collect remaining cases under _ =>, but explicitly enumerating them helps you notice changes.
Exercise 5.1: Define enum Temperature { Cold, Warm, Hot } and write a function returning a different string for each state.