Enums give you a way of saying a value is one of a possible set of values. Rust enums are a slightly more powerful than in other languages. They are more similar to tagged unions in other languages because enum variants can store associated values.
enum IpAddrKind {
V4,
V6,
}
let four = IpAddrKind::V4;
let six = IpAddrKind::V6;
fn route(ip_kind: IpAddrKind) {}
associated values
Each variant in an enum can store an associated value AND these values can be of different types and amounts. The stored enum will be the size of its largest variant plus some room for type information.
enum IpAddr {
V4(u8, u8, u8, u8),
V6(String),
}
let home = IpAddr::V4(127, 0, 0, 1);
let loopback = IpAddr::V6(String::from("::1"));
nesting enums
There's many cases in software development when you have to creation an "optional field" which only applies is some other field is true. Enums in rust help us encode this into the type system and make invalid states unable to be represented. Here's an example of a Coin enum, the quarter, unlike the other coins can come with a variety of patterns for each US state.
#[derive(Debug)]
enum UsState {
Alabama,
Alaska,
// --snip--
}
enum Coin {
Penny,
Nickel,
Dime,
Quarter(UsState),
}
fn value_in_cents(coin: Coin) -> u8 {
match coin {
Coin::Penny => 1,
Coin::Nickel => 5,
Coin::Dime => 10,
Coin::Quarter(state) => {
println!("State quarter from {state:?}!");
25
}
}
}
methods
Enums in rust, like structs, can have methods defined for them:
enum Message {
Quit,
Move { x: i32, y: i32 },
Write(String),
ChangeColor(i32, i32, i32),
}
impl Message {
fn call(&self) {
// method body would be defined here
}
}
let m = Message::Write(String::from("hello"));
m.call();
Option enum
enum Option<T> {
None,
Some(T),
}
The Option type from the standard library encodes the very common scenario in which a value could be something or it could be nothing.
Rust doesn't have the null feature that many other languages have. Null is a value that means there is no value there. In languages with null, variables can always be in one of two states: null or not-null. Rust instead solves this design problem with the Option enum.
The Option<T> enum is so useful that it’s even included in the prelude; you
don’t need to bring it into scope explicitly. Its variants are also included in
the prelude: you can use Some and None directly without the Option:: prefix.
The Option<T> enum is still just a regular enum, and Some(T) and None are
still variants of type Option<T>.