Creating and Using Enums in Rust

Enums (short for enumerations) in Rust are a powerful way to define a type that can be one of several variants. Enums allow you to create a type that can hold different kinds of data, making them useful for representing a value that can be one of a few different options. This is particularly useful in scenarios where you want to model a state or a choice.

1. Basic Syntax of Enums

The basic syntax for defining an enum in Rust is as follows:


enum EnumName {
Variant1,
Variant2,
// Additional variants...
}

Here, EnumName is the name of the enum, and each variant is defined as a possible value of that enum.

2. Example of a Simple Enum

Let's create a simple enum to represent different types of traffic lights:


enum TrafficLight {
Red,
Yellow,
Green,
}

fn main() {
let light = TrafficLight::Red; // Creating an instance of the enum

match light {
TrafficLight::Red => println!("Stop!"),
TrafficLight::Yellow => println!("Caution!"),
TrafficLight::Green => println!("Go!"),
}
}

Explanation of the Example

  • In this example, we define an enum named TrafficLight with three variants: Red, Yellow, and Green.
  • In the main function, we create an instance of the enum by specifying TrafficLight::Red.
  • We then use a match statement to handle each variant of the enum, printing a message based on the current traffic light.

3. Enums with Data

Enums can also hold data associated with their variants. This allows you to store additional information for each variant.

Example of Enums with Data


enum Shape {
Circle(f64), // Circle with radius
Rectangle(f64, f64), // Rectangle with width and height
}

fn area(shape: &Shape) -> f64 {
match shape {
Shape::Circle(radius) => std::f64::consts::PI * radius * radius,
Shape::Rectangle(width, height) => width * height,
}
}

fn main() {
let circle = Shape::Circle(5.0);
let rectangle = Shape::Rectangle(4.0, 6.0);

println!("Area of the circle: {}", area(&circle));
println!("Area of the rectangle: {}", area(&rectangle));
}

Explanation of the Example

  • In this example, we define an enum named Shape with two variants: Circle, which holds a radius, and Rectangle, which holds width and height.
  • The area function takes a reference to a Shape and uses a match statement to calculate the area based on the variant.
  • In the main function, we create instances of Shape for a circle and a rectangle, and then we print their areas using the area function.

4. Enums and Pattern Matching

Enums work seamlessly with pattern matching, allowing you to destructure the data associated with each variant easily. This makes it straightforward to handle different cases based on the enum's current state.

Example of Pattern Matching with Enums


enum Message {
Quit,
ChangeColor(i32, i32, i32), // RGB values
Move { x: i32, y: i32 }, // Named fields
}

fn process_message(msg: Message) {
match msg {
Message::Quit => println!("Quit message received."),
Message::ChangeColor(r, g, b) => println!("Change color to RGB({}, {}, {})", r, g, b),
Message::Move { x, y } => println!("Move to coordinates ({}, {})", x, y),
}
}

fn main() {
let msg1 = Message::Quit;
let msg2 = Message::ChangeColor(255, 0, 0);
let msg3 = Message::Move { x: 10, y: 20 };

process_message(msg1);
process_message(msg2);
process_message(msg3);
}

Explanation of the Example

  • In this example, we define an enum named Message with three variants: Quit, ChangeColor (which holds RGB values), and Move (which has named fields for coordinates).
  • The process_message function takes a Message and uses a match statement to handle each variant, printing appropriate messages based on the variant's data.
  • In the main function, we create instances of Message and call process_message for each instance to demonstrate how the enum and pattern matching work together.

5. Conclusion

Enums in Rust provide a powerful way to define types that can represent multiple variants, with or without associated data. They work seamlessly with pattern matching, making it easy to handle different cases in your code. This feature is particularly useful for modeling complex data and states in a type-safe manner.