Variable is not bound in all patterns

Hi,

I was jut remitting some code and in my attempt to rewrite one of the match blocks that looks something like this:

 let  a = 7u8;
 let  b = 5u8;

match (a,b) {
    (5u8,_) | (7u8,_) | (_,0u8) =>  {println!(">> {}{}", a,b)},
    (9u8,_) => {println!("{} {}", b,a)},
    (_,_) => {println!("bla bla")},
      
  }

into something like this:

  let  x = 5u8;
  let  y = 7u8;
  let  z = 9u8;
  let  a = 7u8;
  let  b = 5u8;
  
  match (a,b) {
    (x,_) | (y,_) | (_,0u8) =>   {println!(">> {}{}", a,b)},
    (z,_) => {println!("{} {}", b,a)},
    (_,_) => {println!("bla bla")},
      
  }

I get:

   Compiling playground v0.0.1 (/playground)
error[E0408]: variable `x` is not bound in all patterns
  --> src/main.rs:11:13
   |
11 |     (x,_) | (y,_) | (_,0u8) =>   {println!(">> {}{}", a,b)},
   |      -      ^^^^^   ^^^^^^^ pattern doesn't bind `x`
   |      |      |
   |      |      pattern doesn't bind `x`
   |      variable not in all patterns

...

My questions are:

  1. What is the problem ?
  2. How to resolve it ?
  3. Is there a better way to do this ?

thank you :slight_smile:

Patterns don't check against existing variables for equality, they bind into new variables. So this for example:

match (a, b) {
    (z, _) => println!("{b} {a}"),
    _ => println!("bla bla"),
}

Doesn't check that z == a, instead the first arm always succeeds and does something analogous to

{
    let (z, _) = (a, b);
    // alternatively spelled:
    // let z = a;
    // let _ = b;
    println!("{b} {a}")
}

and the second arm can never be reached.

With that understanding, the error you're getting is because when you create a new named binding like x for a match arm, it has to be bound in all the patterns of the given arm (and the same type in each). Otherwise you would have a new variable x in the match arm that's not always defined.

For this particular example, since you're not making use of any bindings, I'd probably go with a non-match.

    if a == x || a == y || b == 0 {
        println!("{a} {b}");
    } else if a == z {
        println!("{b} {a}");
    } else {
        println!("bla bla");
    }

You could write it this way instead (though I personally wouldn't):

    match (a, b) {
        _ if a == x || a == y || b == 0 => println!("{a} {b}"),
        _ if a == z => println!("{b} {a}"),
        _ => println!("bla bla"),
    }

consts will work similarly to the literals you originally had; if x, y, and z never change at run time, maybe that's what you're looking for.

    const X: u8 = 5;
    const Y: u8 = 7;
    const Z: u8 = 9;

    let a = 7u8;
    let b = 5u8;

    match (a, b) {
        (X, _) | (Y, _) | (_, 0) => println!("{a} {b}"),
        (Z, _) => println!("{b} {a}"),
        _ => println!("bla bla"),
    }

Playground.

5 Likes