Skip to content

Commit b1eba24

Browse files
author
Dana Binkley
committed
Merge branch 'mr/483-create-lab-for-module-pattern-matching' into 'master'
Resolve "Create Lab for Module: Pattern Matching" Closes #483 See merge request feng/training/material!559
2 parents 6902c22 + f4ff0d3 commit b1eba24

5 files changed

Lines changed: 238 additions & 50 deletions

File tree

Lines changed: 11 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,17 @@
1-
=================================
2-
Exercise: Expression Evaluation
3-
=================================
1+
=====
2+
Lab
3+
=====
44

5-
----------------------------------
6-
Expression Evaluation Background
7-
----------------------------------
5+
------------------
6+
Lab Instructions
7+
------------------
88

9-
Let's write a simple recursive evaluator for arithmetic expressions.
9+
- Solve for compilation errors
1010

11-
An example of a small arithmetic expression could be :rust:`10 + 20`, which
12-
evaluates to :rust:`30`. We can represent the expression as a tree:
11+
- Follow the hints!
1312

14-
.. image:: comprehensive_rust_training/pattern_matching_exercise_1.svg
15-
:width: 40%
13+
- Success is
1614

17-
A bigger and more complex expression would be
18-
:rust:`(10 * 9) + ((3 - 4) * 5)`, which evaluate to :rust:`85`. We represent
19-
this as a much bigger tree:
15+
- Code that compiles
2016

21-
.. image:: comprehensive_rust_training/pattern_matching_exercise_2.svg
22-
23-
---------------------------------
24-
Expression Evaluation Problem
25-
---------------------------------
26-
27-
In code, we will represent the tree with two types:
28-
29-
.. container:: source_include 080_pattern_matching/src/080_pattern_matching.rs :start-after://ANCHOR-operation :end-before://ANCHOR-expression :code:rust
30-
31-
.. container:: source_include 080_pattern_matching/src/080_pattern_matching.rs :start-after://ANCHOR-expression :end-before://ANCHOR-eval :code:rust
32-
33-
And then create an evaluator:
34-
35-
.. code:: rust
36-
37-
fn eval(e: Expression) -> i64 {
38-
todo!()
39-
}
40-
41-
.. container:: source_include 080_pattern_matching/src/080_pattern_matching.rs :start-after://ANCHOR-main :code:rust
42-
43-
.. note:: The :rust:`Box` type here is a smart pointer, and will be covered in detail later in the course. To evaluate a boxed expression, use the deref operator (:rust:`*`) to "unbox" it: :rust:`eval(*boxed_expr)`.
44-
45-
Copy and paste the code into the Rust playground, and begin implementing
46-
:rust:`eval`.
47-
48-
---------------------------------
49-
Expression Evaluation Solution
50-
---------------------------------
51-
52-
.. container:: source_include 080_pattern_matching/src/080_pattern_matching.rs :start-after://ANCHOR-eval :end-before://ANCHOR-tests :code:rust
17+
- ...and that follows any behavior indicated within the hints!

courses/rust_essentials/080_pattern_matching/lab/answer/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[package]
2-
name = "lab"
2+
name = "answer"
33
version = "1.0.0"
44
edition = "2024"
55

Lines changed: 117 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,119 @@
1+
//! Lab (answer)
2+
//! Pattern Matching
3+
//!
4+
#[allow(dead_code)]
5+
#[allow(unused_variables)]
16
fn main() {
2-
println!("TBD");
7+
8+
// TASK 1 - Exhaustiveness in 'match'
9+
// Hint: All possible cases must be handled
10+
enum Status {
11+
Online,
12+
Offline,
13+
Busy,
14+
}
15+
16+
let current_status = Status::Online;
17+
match current_status {
18+
Status::Online => println!("User is online"),
19+
Status::Offline => println!("User is offline"),
20+
// Fix: Added the missing variant to satisfy exhaustiveness
21+
Status::Busy => println!("User is busy"),
22+
}
23+
24+
25+
// TASK 2 - Refutable Pattern in a 'let' Binding
26+
// Hint: Every 'let' binding uses a pattern, but simple bindings require irrefutable patterns
27+
let secret_value = Some(42);
28+
29+
// Fix: Used 'if let' to handle the conditional/refutable pattern
30+
if let Some(x) = secret_value {
31+
println!("The secret is {}", x);
32+
}
33+
34+
35+
// TASK 3 - Ignoring Fields in Struct Destructuring
36+
// Hint: Unused fields may be ignored using rest pattern to capture specific named fields and ignore remaining
37+
struct Player {
38+
name: String,
39+
health: u32,
40+
mana: u32,
41+
}
42+
43+
let p = Player { name: String::from("Hero"), health: 100, mana: 50 };
44+
45+
// Fix: Added '..' to explicitly ignore the 'mana' field
46+
let Player { name, health, .. } = p;
47+
48+
49+
// TASK 4 - Destructuring Variant Data
50+
// Hint: You must keep the parentheses for variants with data, even if you are ignoring the content
51+
enum Alert {
52+
Clear,
53+
Warning(String),
54+
}
55+
56+
let a = Alert::Warning(String::from("Low Battery"));
57+
match a {
58+
// Fix: Added '(_)' to properly account for the payload while ignoring it
59+
Alert::Warning(_) => println!("Received a warning, ignoring details"),
60+
Alert::Clear => println!("All clear"),
61+
}
62+
63+
64+
// TASK 5 - Match Guards and Exhaustiveness
65+
// Hint: Guards are dynamic, compiler usually requires a "catch-all" arm (_) when using match guards
66+
let temperature = 30;
67+
match temperature {
68+
t if t > 25 => println!("Hot"),
69+
t if t <= 25 => println!("Cool"),
70+
_ => unreachable!(), // Fix: Added the wildcard '_' catch-all arm
71+
}
72+
73+
74+
// TASK 6 - Longhand Struct Destructuring and Renaming
75+
// Hint: Use 'field: variable' to rename data as it is extracted
76+
struct Coordinates {
77+
x: i32,
78+
y: i32,
79+
}
80+
81+
let c = Coordinates { x: 5, y: 10 };
82+
// Fix: Swapped the order to correctly map the struct fields to the new local variables
83+
let Coordinates { x: my_x, y: my_y } = c;
84+
85+
println!("The coordinates are: {},{}", my_x, my_y);
86+
87+
88+
// TASK 7 - Destructuring Struct Variants
89+
// Hint: Struct variants use named fields, patterns must match fields by name using {} instead of ()
90+
enum Geometry {
91+
Rectangle { width: u32, height: u32 },
92+
}
93+
94+
let geo = Geometry::Rectangle { width: 10, height: 20 };
95+
match geo {
96+
// Fix: Changed the tuple syntax '()' to struct syntax '{}'
97+
Geometry::Rectangle { width, height } => println!("{}x{}", width, height),
98+
}
99+
100+
101+
// TASK 8 - "if let" Syntax Order
102+
// Hint: "if let" follows assignment order: Pattern = value
103+
let optional_code = Some(777);
104+
105+
// Fix: Reordered the expression so the pattern is on the left and the value is on the right
106+
if let Some(code) = optional_code {
107+
println!("Code is {}", code);
108+
}
109+
110+
111+
// TASK 9 - Variable Bindings with Ranges
112+
// Hint: Use the '@' operator to give a name to a value while checking it against a range
113+
let dice_roll = 4;
114+
match dice_roll {
115+
// Fix: Placed the identifier 'roll' before the '@' and the range pattern
116+
roll @ 1..=6 => println!("Rolled a {}", roll),
117+
_ => println!("Invalid roll"),
118+
}
3119
}

courses/rust_essentials/080_pattern_matching/lab/prompt/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[package]
2-
name = "lab"
2+
name = "prompt"
33
version = "1.0.0"
44
edition = "2024"
55

Lines changed: 108 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,110 @@
1+
//! Lab (prompt)
2+
//! Pattern Matching
3+
//!
4+
//! Fix all the compile errors below by following the hints provided
5+
//!
6+
#[allow(dead_code)]
7+
#[allow(unused_variables)]
18
fn main() {
2-
println!("TBD");
9+
10+
// TASK 1 - Exhaustiveness in 'match'
11+
// Hint: All possible cases must be handled
12+
enum Status {
13+
Online,
14+
Offline,
15+
Busy,
16+
}
17+
18+
let current_status = Status::Online;
19+
match current_status {
20+
Status::Online => println!("User is online"),
21+
Status::Offline => println!("User is offline"),
22+
}
23+
24+
25+
// TASK 2 - Refutable Pattern in a 'let' Binding
26+
// Hint: Every 'let' binding uses a pattern, but simple bindings require irrefutable patterns
27+
let secret_value = Some(42);
28+
29+
let Some(x) = secret_value;
30+
println!("The secret is {}", x);
31+
32+
33+
// TASK 3 - Ignoring Fields in Struct Destructuring
34+
// Hint: Unused fields may be ignored using rest pattern to capture specific named fields and ignore remaining
35+
struct Player {
36+
name: String,
37+
health: u32,
38+
mana: u32,
39+
}
40+
41+
let p = Player { name: String::from("Hero"), health: 100, mana: 50 };
42+
43+
let Player { name, health } = p;
44+
45+
46+
// TASK 4 - Destructuring Variant Data
47+
// Hint: You must keep the parentheses for variants with data, even if you are ignoring the content
48+
enum Alert {
49+
Clear,
50+
Warning(String),
51+
}
52+
53+
let a = Alert::Warning(String::from("Low Battery"));
54+
match a {
55+
Alert::Warning => println!("Received a warning, ignoring details"),
56+
Alert::Clear => println!("All clear"),
57+
}
58+
59+
60+
// TASK 5 - Match Guards and Exhaustiveness
61+
// Hint: Guards are dynamic, compiler usually requires a "catch-all" arm (_) when using match guards
62+
let temperature = 30;
63+
match temperature {
64+
t if t > 25 => println!("Hot"),
65+
t if t <= 25 => println!("Cool"),
66+
}
67+
68+
69+
// TASK 6 - Longhand Struct Destructuring and Renaming
70+
// Hint: Use 'field: variable' to rename data as it is extracted
71+
struct Coordinates {
72+
x: i32,
73+
y: i32,
74+
}
75+
76+
let c = Coordinates { x: 5, y: 10 };
77+
let Coordinates { my_x: x, my_y: y } = c;
78+
79+
println!("The coordinates are: {},{}", my_x, my_y);
80+
81+
82+
// TASK 7 - Destructuring Struct Variants
83+
// Hint: Struct variants use named fields, patterns must match fields by name using {} instead of ()
84+
enum Geometry {
85+
Rectangle { width: u32, height: u32 },
86+
}
87+
88+
let geo = Geometry::Rectangle { width: 10, height: 20 };
89+
match geo {
90+
Geometry::Rectangle(width, height) => println!("{}x{}", width, height),
91+
}
92+
93+
94+
// TASK 8 - "if let" Syntax Order
95+
// Hint: "if let" follows assignment order: Pattern = value
96+
let optional_code = Some(777);
97+
98+
if let optional_code = Some(code) {
99+
println!("Code is {}", code);
100+
}
101+
102+
103+
// TASK 9 - Variable Bindings with Ranges
104+
// Hint: Use the '@' operator to give a name to a value while checking it against a range
105+
let dice_roll = 4;
106+
match dice_roll {
107+
1..=6 @ roll => println!("Rolled a {}", roll),
108+
_ => println!("Invalid roll"),
109+
}
3110
}

0 commit comments

Comments
 (0)