Guide

Enums and Option

A struct has all of its fields at once. An enum is exactly one of its variants at a time.

Defining enums

List the variants inside the braces. Name a variant with the enum name and ::.

enum Dir {    North,    South,}let d = Dir::North;

A Dir is always North or South, never both.

Variants with data

Each variant can carry its own data. A variant can look like a tuple, look like a struct, or hold nothing.

enum Shape {    Circle(f64),    Rect { w: f64, h: f64 },    Empty,}let s = Shape::Rect { w: 2.0, h: 3.0 };

All three are the same type, Shape, so they can share one Vec<Shape>.

Option

Rust has no null. A value that might be missing has type Option<T>. It is an enum with two variants: Some(value) and None.

let found: Option<i32> = Some(5);let empty: Option<i32> = None;

You don't write Option:: before Some and None. You can't use an Option<i32> as an i32; deal with None first. A bare let x = None; is E0282: Rust can't tell the type, so write Option<i32>.

Option methods

You don't always need a full match.

  • is_some() and is_none() ask which variant it is.
  • unwrap_or(x) gives the value, or x if it is None.
  • map(f) runs f on the value inside a Some and leaves None alone.
  • unwrap() gives the value, but crashes on None. expect("msg") is the same, with your message.
fn double(n: i32) -> i32 { n * 2 }let a = Some(4).map(double); // Some(8)let b: Option<i32> = None;let c = b.unwrap_or(0);      // 0

Methods on enums

Enums can have impl blocks, just like structs. &self, &mut self, self and associated functions all work the same way.

#[derive(Debug)]enum Door { Open, Shut }impl Door {    fn new() -> Self { Door::Shut }    fn open(&mut self) { *self = Door::Open; }}

*self is the value itself, so *self = Door::Open; swaps in a new variant. To act differently for each variant, you need match (next unit).

Remember

  • An enum value is one variant at a time.
  • Write variants as Enum::Variant.
  • Use Option<T> instead of null.
  • unwrap_or gives a safe fallback for None.