# Pattern Syntax Here we gather all the syntax valid in patterns and discuss why and when you might want to use each one. ## Matching Literals As you saw previously in Ch6, you can match patterns against literals directly. Here is an example of this ```rust let x = 1; match x { 1 => println!("one"), 2 => println!("two"), 3 => println!("three"), _ => println!("anything"), } ``` The code prints `one` because the value in `x` is 1. This syntax is useful when you want your code to take an action if it gets a particular concrete value. ## Matching Named Variables Named variables are irrefutable patterns that match any value, and we have used them many times. However, there is a complication when you use named variables in `match`, `if let`, or `while let` expressions. Because each kinds of expression starts a new scope, variables declared as part of a pattern inside the expression will shadow those with the same name outside, as is the case with all variables. Here we declare a variable named `x` with the value `Some(5)` and a variable `y` with the value `10`. Next we create a `match` expression on the value `x`. Look at the patterns in the match arms and `println!` at the end, and try to figure out what the code will print before running this code or reading further. ```rust let x = Some(5); let y = 10; match x { Some(50) => println!("Got 50"), Some(y) => println!("Matched, y = {y}"), _ => println!("Default case, x = {x:?}"), } println!("at the end: x = {x:?}, y = {y}"); ``` Lets run through what happens when the `match` expression runs. The pattern in the first match arm doesn't match the defined value of `x`, so the code continues. The pattern in the second match arm introduces a new variable named `y` that will match any value inside a `Some` value. Because we are in a new scope inside the `match` expression, this is a new `y` variable, not the `y` we declared at the beginning with the value 10. This new `y` binding will match any value inside a `Some`, which is what we have in `x`. Therefore the new `y` binds to the inner value of the `Some` in `x`. That value is `5` so the expression for that arm executes and prints `Matched , y = 5`. If `x` has been a `None` value instead of `Some(5)`, the patterns in the first two arms wouldn't have matched. so the value would have matched to the underscore. We didn't introduce the `x` variable in the pattern of the underscore arm, so the `x` in the expression is still the outer `x` that hasn't been shadowed. For this hypothetical case, the `maatch` would pint `Default case, x = None`. When the `match` expression is done, its scope ends, and so does the scope of the inner `y`. The last `println!` produces `at the end: x = Some(5), y = 10`. To create a `match` expression that compares the values of the outer `x` and `y` rather than introducing a new variable which shadows the exiting `y` variable. We would need to use a match guard conditional instead. This will be covered later in the ch. ## Multiple Patterns You can match multiple patterns using the `|` syntax, which is the pattern *or* operator. For example in the following code we match the value of `x` against the match arms, the first of which has an *or* option, meaning if the value of `x` matches either of the values in that arm, that arm's code will run ```rust let x = 1; match x { 1 | 2 => println!("one or two"), 3 => println!("three"), _ => println!("anything"), } ``` This code prints `one or two`. ## Matching Ranges of Values with `..=` The `..=` syntax allows us to match to an inclusive range of values. Here when a pattern matches any of the values within the given range, that arm will execute ```rust let x = 5; match x { 1..=5 => println!("one through five"), _ => println!("something else"), } ``` If `x` is 1, 2, 3, 4, or 5, the first arm will match. This syntax is more convenient for multiple match values that using the `|` operator to express the same idea. If we were to use `|` we would need to do `1 | 2 | 3 | 4 | 5`. Specifying a range is much shorter, especially if we want to match, say any number between 1 and 1,000. The compiler checks that the range isn't empty at compile time, because only types for which Rust can tell if a range is empty or not are `char` and numeric values, ranges are only allowed with numeric or `car` values. Rust can tell that `'c'` is within the first pattern's range and prints `early ASCII letter`. ## Destructuring to Break Apart Values We can also use patterns to destructure structs, enums, and tuples to use different parts of these values. We will walk through each value. ### Destructuring Structs This code shows a `Point` struct with two fields, `x` and `y`, that we can break apart using a patter with a `let` statement ```rust struct Point { x: i32, y: i32, } fn main() { let p = Point { x: 0, y: 7 }; let Point { x: a, y: b } = p; assert_eq!(0, a); assert_eq!(7, b); } ``` This creates the variables `a` and `b` that match the values of the `x` and `y` fields of the `p` struct. This shows that the names of the variables in the pattern don't have to match the field names of the struct. However it is common to match the variable names to the field names to make it easier to remember which variables came from which fields. Because of this common usage, and because writing `let Point { x: x, y: y} = p;` contains a lot of duplication, Rust has a shorthand for patterns that match struct fields. You only need to list the name of the struct field, and the variables created from the pattern will have the same names. This code behaves in the same way as om the code before, but the variables created in the `let` pattern are `x` and `y` instead of `a` and `b`. ```rust struct Point { x: i32, y: i32, } fn main() { let p = Point { x: 0, y: 7 }; let Point { x, y } = p; assert_eq!(0, x); assert_eq!(7, y); } ``` This code creates the variables `x` and `y` that match the `x` and `y` fields of the `p` variable. The outcome is that the variables `x` and `y` contain the values form the `p` struct. We can also destructure with literal values as part of the struct pattern rather than creating variables for all the fields. Doing this allows us to test some of the fields for particular values while creating variables to destructure the other fields. Here we have a `match` expression that separates `Point` values into three cases. Points that lie directly on the `x` axis (which is true when `y = 0`) On the `y` axis (`x = 0`) Or Neither ```rust fn main() { let p = Point { x: 0, y: 7 }; match p { Point { x, y: 0 } => println!("On the x axis at {x}"), Point { x: 0, y } => println!("On the y axis at {y}"), Point { x, y } => { println!("On neither axis: ({x}, {y})"); } } } ``` The first arm will match any point that lies on the `x` axis by specifying that the `y` field matches if its value matches the literal `0`. The pattern still creates an `x` variable that we can use in the code for this arm. The second arm matches any point on the `y` axis by specifying that the `x` field matches if its value is `0` and creates a variable `y` for the value of the `y` field. The third arm doesn't specify any literals, so it matches any other `Point` and creates variables that we can use in the code for this arm. Here the value `p` matches the second arm by virtue of `x` containing a 0, so this code will print `On the x axis at 0`. ### Destructuring Enums We have destructured enums before, but haven't explicitly discussed that the pattern to destructure an enum corresponds to the way the data stored within the enum is defined. For example, here we use the `Message` enum from Ch6 and write a `match` with patterns that will destructure each inner value. ```rust enum Message { Quit, Move { x: i32, y: i32 }, Write(String), ChangeColor(i32, i32, i32), } fn main() { let msg = Message::ChangeColor(0, 160, 255); match msg { Message::Quit => { println!("The Quit variant has no data to destructure."); } Message::Move { x, y } => { println!("Move in the x direction {x} and in the y direction {y}"); } Message::Write(text) => { println!("Text message: {text}"); } Message::ChangeColor(r, g, b) => { println!("Change the color to red {r}, green {g}, and blue {b}"); } } } ``` This code will print `Change the color to red 0, green 160, and blue 255`. Try changing the value of `msg` to see the code form the other arms run. For enum variants without any data, like `Message::Quit`. We can't destructure the value any further. We can only match on the literal `Message::Quit` value and no variables are in that pattern. For struct-like enum variants, like `Message::Move`. We can use a pattern similar to the pattern we specify to match structs. After the variant name, we place curly brackets and then list the fields with variable so we break apart the pieces to use in the code for this arm. We did use the shorthand form as we did before. For tuple-like enum variants, like `Message::Write` that holds a tuple with one element and `Message::ChangeColor` that holds a tuple with three elements. The pattern is similar to the pattern we specify to match tuples. The number of variables in the pattern must match the number of elements in the variant we are matching. ### Destructuring Nested Structs and Enums