Enums and Matching Pattern
Enums:
Enums (short for "enumerations") are types that allow you to define a value that can be one of several variants.
Multiple variants types in single enum:
enum Message { Quit, // No data Move { x: i32, y: i32 }, // Named fields Write(String), // Single unnamed field ChangeColor(u8, u8, u8), // Multiple unnamed fields }
Matching Pattern:
Matching pattern syntax allows you to compare a value against a series of patterns and execute code based on the matching pattern.
You can destructure complex data types like structs, enums, and tuples in a
match
.You can add conditions to patterns using
if
guards.
Reference:
enums1.rs
#[derive(Debug)]
enum Message {
// Define a few types of messages as used below.
Resize,
Move,
Echo,
ChangeColor,
Quit,
}
fn main() {
println!("{:?}", Message::Resize);
println!("{:?}", Message::Move);
println!("{:?}", Message::Echo);
println!("{:?}", Message::ChangeColor);
println!("{:?}", Message::Quit);
}
In this exercise we need to define types of messages as used in the
main
function.So we simply add all of the types available in the main function into enum definition.
enums2.rs
#[derive(Debug)]
struct Point {
x: u64,
y: u64,
}
#[derive(Debug)]
enum Message {
// Define the different variants used below.
Resize { width: i32, height: i32 },
Move(Point),
Echo(String),
ChangeColor(i32, i32, i32),
Quit,
}
impl Message {
fn call(&self) {
println!("{self:?}");
}
}
fn main() {
let messages = [
Message::Resize {
width: 10,
height: 30,
},
Message::Move(Point { x: 10, y: 15 }),
Message::Echo(String::from("hello world")),
Message::ChangeColor(200, 255, 255),
Message::Quit,
];
for message in &messages {
message.call();
}
}
We can have multiple variants types in single enum.
In this task we need to write 5 variants.
enum Message { Resize { width: i32, height: i32 }, // with named field data like a struct Move(Point), // has a struct data Echo(String), // has a single String data ChangeColor(i32, i32, i32), // has 3 data like a tuple Quit, // no data }
enums3.rs
struct Point {
x: u64,
y: u64,
}
enum Message {
Resize { width: u64, height: u64 },
Move(Point),
Echo(String),
ChangeColor(u8, u8, u8),
Quit,
}
struct State {
width: u64,
height: u64,
position: Point,
message: String,
// RGB color composed of red, green and blue.
color: (u8, u8, u8),
quit: bool,
}
impl State {
fn resize(&mut self, width: u64, height: u64) {
self.width = width;
self.height = height;
}
fn move_position(&mut self, point: Point) {
self.position = point;
}
fn echo(&mut self, s: String) {
self.message = s;
}
fn change_color(&mut self, red: u8, green: u8, blue: u8) {
self.color = (red, green, blue);
}
fn quit(&mut self) {
self.quit = true;
}
fn process(&mut self, message: Message) {
// TODO: Create a match expression to process the different message
// variants using the methods defined above.
match message {
Message::Resize {
width: w,
height: h,
} => self.resize(w, h),
Message::Move(p) => self.move_position(p),
Message::Echo(s) => self.echo(s),
Message::ChangeColor(r, g, b) => self.change_color(r, g, b),
Message::Quit => self.quit(),
}
}
}
fn main() {
// You can optionally experiment here.
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_match_message_call() {
let mut state = State {
width: 0,
height: 0,
position: Point { x: 0, y: 0 },
message: String::from("hello world"),
color: (0, 0, 0),
quit: false,
};
state.process(Message::Resize {
width: 10,
height: 30,
});
state.process(Message::Move(Point { x: 10, y: 15 }));
state.process(Message::Echo(String::from("Hello world!")));
state.process(Message::ChangeColor(255, 0, 255));
state.process(Message::Quit);
assert_eq!(state.width, 10);
assert_eq!(state.height, 30);
assert_eq!(state.position.x, 10);
assert_eq!(state.position.y, 15);
assert_eq!(state.message, "Hello world!");
assert_eq!(state.color, (255, 0, 255));
assert!(state.quit);
}
}
In this exercise we need to create matching pattern syntax for all the available variants in
Message
enum and call it's respective method.For each variants that have data, we want to catch or get that data so we can use it as arguments when calling it's respective method.
match message { // bind width -> w and height -> h Message::Resize { width: w, height: h } => self.resize(w, h), // bind Point -> p Message::Move(p) => self.move_position(p), // bind String -> s Message::Echo(s) => self.echo(s), // bind first value -> r // bind second value -> r // bind third value -> r Message::ChangeColor(r, g, b) => self.change_color(r, g, b), Message::Quit => self.quit(), }
This pattern syntax will bind data in the message enum variants into the defined variables.
Last updated