Reputation: 192
Rust noob here. I am puzzled as to why I get this strange behaviour when matching the variable over which I am iterating through a range, with the max of that range. Instead of only matching with the last item, it matches everything! Can someone please explain the output and compiler warning I get from this code:
fn main() {
let maxi = 2;
for i in 0..=maxi {
match i {
maxi => {
println!("i={} matched maxi={}",i,maxi);
}
_ => {
println!("i={} matched with _",i);
}
}
}
}
The compiler output is as follows
warning: unreachable pattern
--> se_match_loop.rs:7:15
|
5 | maxi => {
| ---- matches any value
6 | println!("i={} matched maxi={}",i,maxi);
7 | } _ => {
| ^ unreachable pattern
|
= note: `#[warn(unreachable_patterns)]` on by default
warning: 1 warning emitted
When I execute the compiled script, this is the output
i=0 matched maxi=0
i=1 matched maxi=1
i=2 matched maxi=2
But if I declare maxi
as a constant (with const
instead of let
), I get the expected output
i=0 matched _
i=1 matched _
i=2 matched maxi=2
Upvotes: 1
Views: 822
Reputation: 24592
This is documented under Matching Named Variablesdoc.rust-lang.org.
match
starts a new scope, variables declared as part of a pattern inside thematch
expression will shadow those with the same name outside the match construct, as is the case with all variables.For example, the following code
fn main() { 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 = {:?}, y = {:?}", x, y); }
will print
Matched, y = 5 at the end: x = Some(5), y = 10
Now let's consider your first snippet,
fn main() {
let maxi = 2;
for i in 0..=maxi {
match i {
maxi => {
println!("i={} matched maxi={}",i,maxi);
}
_ => {
println!("i={} matched with _",i);
}
}
}
}
The pattern in your match
arm introduces a new variable(Remember match
started with a new scope) named maxi
that will match any value. That's why the rust compiler emits the following warning with your first snippet.
warning: unreachable pattern
--> se_match_loop.rs:7:15
|
5 | maxi => {
| ---- matches any value
6 | println!("i={} matched maxi={}",i,maxi);
7 | } _ => {
| ^ unreachable pattern
|
= note: `#[warn(unreachable_patterns)]` on by default
warning: 1 warning emitted
Now lets consider the second one(with const
),
fn main() {
const maxi: i32 = 2;
for i in 0..=maxi {
match i {
maxi => {
println!("i={} matched maxi={}",i,maxi);
}
_ => {
println!("i={} matched with _",i);
}
}
}
}
This will work as expected because constants are inlined wherever they’re used, making using them identical to simply replacing the name of the const
with its valuedoc.rust-lang.org
Upvotes: 7