Skip to content

Enums

An enum is a type with a fixed set of named variants. Variant names are snake_case, and a variant may carry a payload. Enums are built for match.

enum Status {
active
suspended
closed
}

A variant can carry named fields:

enum Payment {
cash
card(number: string)
transfer(iban: string, amount: decimal)
}
fn describe(p: Payment) -> string {
return match p {
cash => "cash",
card(n) => "card ending {n.last(4)}",
transfer(iban, amt) => "sent {amt} to {iban}",
}
}

Construct a variant with the enum name in front: Payment.card("4242"), or Payment.cash for a variant with no payload. Matching, by contrast, uses the bare variant name. It binds the payload fields positionally (card(n)), and the matched value pins their types, so you do not restate them.

Enums are objects too. They can carry methods, with an implicit self:

enum Level {
low
high
fn label() -> string {
return match self {
low => "low",
high => "high",
}
}
}

Option<T> and Result<T, E> are ordinary builtin enums:

enum Option<T> {
some(value: T)
none
}
enum Result<T, E> {
ok(value: T)
err(error: E)
}

That is why some, none, ok, and err are lowercase: they are variant values, and variants are snake_case. See Option and Result.

An enum with payloads and a method, matched to compute a value:

import std.io
enum Shape {
circle(r: f64)
rect(w: f64, h: f64)
fn area() -> f64 {
return match self {
circle(r) => 3.14159 * r * r,
rect(w, h) => w * h,
}
}
}
fn main() {
let s: Shape = Shape.rect(3.0, 4.0)
io.println("{s.area()}")
}

A match on an enum must cover every variant, or handle the rest with _. See Pattern matching.