Hello! I'm a total Rust n00b and I'm reading the Rust Programming Language book and I'm up to the match operator. I don't understand why these two examples behave differently.
In this first example nothing matched is printed as I expected.
fn main() {
let x = 5;
match x {
7 => println!("seven"),
_ => println!("nothing matched!")
}
}
But why is it that in this second example seven is printed? All I did was replace the value 7 with a variable containing the value 7
fn main() {
let x = 5;
let y = 7;
match x {
y => println!("seven"),
_ => println!("nothing matched!")
}
}
Here is what I think is happening. In the first example matching happens based on the value(s) of the arm(s) while in the second example matching happens based on type. Assuming what I think is happening is correct I don't understand why using a variable changes the evaluation from value to type.
Thank you for your consideration of my n00b question.
The thing on the left (7 in the first example, y in the second) is a pattern. 7 is a pattern that matches when the thing is 7; y is a pattern that always matches and binds the value to the name y.
If you wanted to match on values that are equal to a variable, you'd do
match x {
x if x == y => println!("seven"),
_ => println!("nothing matched!"),
}
Basically, the pattern describes the shape that it's matching on, and an identifier will match anything (this is useful because you can nest patterns, so (a, 5) is a pattern that matches a tuple where the second element is 5 and binds the first value to the name a.)
The compiler emits a bunch of warning that should hopefully make things a bit clearer:
warning: unreachable pattern
--> src/main.rs:6:9
|
5 | y => println!("seven"),
| - matches any value
6 | _ => println!("nothing matched!")
| ^ unreachable pattern
|
= note: `#[warn(unreachable_patterns)]` on by default
warning: unused variable: `y`
--> src/main.rs:3:9
|
3 | let y = 7;
| ^ help: if this is intentional, prefix it with an underscore: `_y`
|
= note: `#[warn(unused_variables)]` on by default
warning: unused variable: `y`
--> src/main.rs:5:9
|
5 | y => println!("seven"),
| ^ help: if this is intentional, prefix it with an underscore: `_y`
warning: 3 warnings emitted
Both ys are unused, which means that the second y introduces a new variable that is unrelated (and shadows) the first variable. A better message may be along the lines of warning: pattern introduces a name that shadows a variable.
I didn't read the warnings because I'm executing this in a file with a bunch of toy functions from the book that aren't used so I get a bunch of warnings.
What's interesting to me is that I woke up this morning with the sudden realization of what you've described (i.e., shadowing). So before I got on here I tweaked the code to test if y was being shadowed. This realization puts be back into a head space where I'm back to being unsure how match works in my example. But a lot of info from all you beautiful ppl have been provided so here is how I think it works now. Please confirm/deny.
In a match block the use of a variable will ALWAYS match and capture (or be bound to) the value being matched against?
Yes, I believe that’s correct. One way to think about this is that patterns always behave the same way, and let x = something() is also a pattern-matching construct, so
Yes, unless some other pattern matches it first. For example:
match x {
42 => println!("You guess the right answer!"),
y => println!("You guessed {}. Guess again.", y),
}
The patterns are checked in order from top to bottom. If x is 42, the first pattern will match, and the second one won't be checked. If x is any other value, then the first pattern will fail, and the second pattern will match (because y is a pattern that matches any value).