dcxst
dcxst

Reputation: 192

Strange matching behaviour in for loop

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

Answers (1)

user459872
user459872

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 the match 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

Related Questions