Discrete Value constraints in rust: Enum and Option

Amay B
CoderHack.com
Published in
3 min readSep 22, 2023

--

Photo by Kadarius Seegars on Unsplash

Enums are a powerful feature of Rust for defining types that can have a fixed set of possible variants. They are useful for modeling a type that can have a few distinct states.

In this article, we’ll explore:

  1. Simple enums with unit variants
  2. Enums with data
  3. Iterating over enum variants
  4. Defining enum values
  5. Enum types
  6. The Option enum
  7. Unwrapping and matching on Option enums

Simple Enums with Unit Variants

We can define an enum with a few unit variants (that carry no data) like this:

enum Direction {
North,
South,
East,
West,
}

This enum has four possible variants: North, South, East and West.

Enums with Data

Enums can also store data. We can add variants that carry data like this:

enum Message {
Quit,
Move { x: i32, y: i32 },
Write(String),
ChangeColor(i32, i32, i32),
}

Here, the Quit variant has no data, but the Move variant carries two i32 fields, x and y. The Write variant carries a String and the ChangeColor variant carries three i32 RGB color values.

We can use enums with data to model complex types in our code.

Iterating Over Enum Variants

We can create arrays of enums and iterate over their variants. For example:

enum Direction {
North,
South,
East,
West,
}

let directions = [Direction::North, Direction::South, Direction::East, Direction::West];

for direction in directions {
match direction {
Direction::North => println!("Go north"),
Direction::South => println!("Go south"),
Direction::East => println!("Go east"),
Direction::West => println!("Go west"),
}
}

This will print:

Go north 
Go south
Go east
Go west

Defining Enum Values

We can define variables to hold enum variants like this:

enum TrafficLight {
Red,
Yellow,
Green,
}

let red = TrafficLight::Red;

Now red holds the TrafficLight::Red variant.

Enum Types

Enum variants have a type defined by the enum. For example:

enum TrafficLight {
Red,
Yellow,
Green,
}

let red: TrafficLight = TrafficLight::Red;

Here red has the type TrafficLight.

The Option Enum

Rust has a very useful built-in enum called Option. It is defined as:

enum Option<T> {
None,
Some(T),
}

The Option enum is used to represent optional values. The Some variant holds a value of type T, while the None variant is empty.

Option<T> is used a lot in Rust code to represent values that may or may not exist.

Unwrapping Options

We can unwrap options using the unwrap() method or with pattern matching. For example:

let some_number = Some(5);
let some_string = Some("a string");

let absent_number: Option<i32> = None;

match some_number {
Some(num) => println!("The number is {:?}", num),
None => println!("Option is empty!"),
}

let x = some_number.unwrap(); // x = 5

Calling unwrap() on some_number will give us the inner value of 5, and assign it to x.

However, calling unwrap() on an Option that is None will panic! So we have to handle the None case.

Option Enums with Match

A safer way to handle Options is to use pattern matching with match. For example:

enum Option<T> {
None,
Some(T),
}

let coin = Some(1);
let another_coin = None;

match coin {
Some(num) => println!("You have {} coins!", num),
None => println!("No coins!"),
}

match another_coin {
Some(num) => println!("You have {} other coins!", num),
None => println!("No other coins!"),
}

This will print:

You have 1 coins!
No other coins!

Pattern matching allows us to handle the None case gracefully without panicking.

Conclusion

Enums are a very useful feature of Rust for modeling types that can be one of a few variants. The Option enum is especially useful for representing optional values in Rust code. I hope this helps you in your Rust programming! Let me know if you have any other questions.

--

--