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
  • 326,504
  • 69
  • 892
  • 1,159
user1244932
  • 6,781
  • 3
  • 37
  • 88

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 - Krabbe mit Hüten
  • 24,143
  • 12
  • 85
  • 121