0

I have this simple code:

#[derive(Copy, Clone, Default, PartialEq, PartialOrd, Eq, Ord, Hash)]
struct NodeIndex(u32);

fn main() {
    let i = NodeIndex(5323);
    let from = NodeIndex(21030);
    let to = NodeIndex(21031);

    println!("from == i => {}, to == i => {}", from == i, to == i);

    match i {
        from => println!("1"),
        to => println!("2"),
        _ => println!("other"),
    }
}

it prints:

from == i => false, to == i => false
1

so i != from, i != to, but match call from => println!("1"),, what is going on?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
user1244932
  • 7,352
  • 5
  • 46
  • 103

1 Answers1

7

It might be easier to understand what's going on by looking at the compiler's warnings:

warning: unused variable: `from`
  --> src/main.rs:12:9
   |
12 |         from => println!("1"),
   |         ^^^^
   |
   = note: #[warn(unused_variables)] on by default

warning: unreachable pattern
  --> src/main.rs:13:9
   |
13 |         to => println!("2"),
   |         ^^ this is an unreachable pattern
   |
   = note: #[warn(unreachable_patterns)] on by default
note: this pattern matches any value
  --> src/main.rs:12:9
   |
12 |         from => println!("1"),
   |         ^^^^

warning: unused variable: `to`
  --> src/main.rs:13:9
   |
13 |         to => println!("2"),
   |         ^^
   |
   = note: #[warn(unused_variables)] on by default

warning: unreachable pattern
  --> src/main.rs:14:9
   |
14 |         _ => println!("other"),
   |         ^ this is an unreachable pattern
   |
   = note: #[warn(unreachable_patterns)] on by default
note: this pattern matches any value
  --> src/main.rs:12:9
   |
12 |         from => println!("1"),
   |         ^^^^

Basically, the identifiers from and to do not refer to the values contained in the bindings. They are new bindings that happen to match anything. The same thing happens with new identifier names:

match i {
    x => println!("1"),
    y => println!("2"),
    _ => println!("other"),
}

Since the program always matches the first case, "1" is always printed.

You can get the expected result by declaring from and to as const:

const from: NodeIndex = NodeIndex(21030);
const to: NodeIndex = NodeIndex(21031);

Or by using object literals directly:

match i {
    NodeIndex(21030) => println!("1"),
    NodeIndex(21031) => println!("2"),
    _ => println!("other"),
}

If the values of from and to are only known in runtime, you can use if/else statements:

if n == from {
    println!("1");
} else if n == to {
    println!("2");
} else {
    println!("other");
}

... or add if clauses during the match (which are evaluated in run-time):

match i {
    n if n == from => println!("1"),
    n if n == to => println!("2"),
    _ => println!("other"),
}
E_net4
  • 27,810
  • 13
  • 101
  • 139
  • Thanks, actually I can not use `const`, because of I calculate those values in real program, so I have to use `if else` in this case? – user1244932 Jul 03 '17 at 16:01
  • @user1244932, you can use `match i { x if x == v1 => ... , x if x == v2 => ...,}` syntax – red75prime Jul 03 '17 at 16:03
  • @user1244932 I've updated the answer. Indeed, you can either use if/else or add `if` clauses to the match cases. – E_net4 Jul 03 '17 at 16:06