Discrete Value constraints in rust: Enum and Option
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:
- Simple enums with unit variants
- Enums with data
- Iterating over enum variants
- Defining enum values
- Enum types
- The Option enum
- 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.