为什么使用匹配时参数的顺序很重要!宏?

eld*_*orz 1 comparison enums rust

我试图将存储在结构向量中的枚举类型变量与作为参数传递到我的函数中的相同类型的变量进行比较。因此,两个枚举都存储在变量中。然而,我得到了意想不到的结果。我使用matches!()宏来进行比较。谁能解释这种行为?

enum Foo {
    A,
    B,
}


fn main() {
    let a = Foo::A;
    if matches!(a, Foo::A) { println!("expected") }
    if matches!(a, Foo::B) { println!("not expected 1") }
    if matches!(Foo::B, a) { println!("not expected 2") }

    let b =  Foo::B;
    if matches!(a, b) { println!("not expected 3") }
}
Run Code Online (Sandbox Code Playgroud)

输出:

enum Foo {
    A,
    B,
}


fn main() {
    let a = Foo::A;
    if matches!(a, Foo::A) { println!("expected") }
    if matches!(a, Foo::B) { println!("not expected 1") }
    if matches!(Foo::B, a) { println!("not expected 2") }

    let b =  Foo::B;
    if matches!(a, b) { println!("not expected 3") }
}
Run Code Online (Sandbox Code Playgroud)

E_n*_*ate 5

matches!宏不是对称的:第一个操作数是要测试的表达式,第二个操作数是尝试匹配第一个操作数的模式。如果不遵守这个顺序,结果可能会出乎意料。

虽然前两个matches!结构良好并且符合您的预期,但第三个和第四个很可能不是您想要的。

matches!(Foo::B, a) // test `Foo::B` against pattern `a`
matches!(a, b) // test `a` against pattern `b`
Run Code Online (Sandbox Code Playgroud)

在第三个示例和第四个示例中,要测试的表达式是文字值Foo::B,模式是新标识符。由于模式只是一个标识符,因此它将匹配任何表达式。它与预先声明的变量完全无关。即使不存在,下面的代码仍然可以编译。ababb

let a = Foo::A;
matches!(a, b);
Run Code Online (Sandbox Code Playgroud)

另请注意,这些if语句将打印警告,因为新变量是根据模式创建的,但未使用。

warning: unused variable: `a`
 --> src/main.rs:7:25
  |
7 |     if matches!(Foo::B, a) { println!("not expected 2") }
  |                         ^ help: if this is intentional, prefix it with an underscore: `_a`
  |
  = note: `#[warn(unused_variables)]` on by default
Run Code Online (Sandbox Code Playgroud)

也可以看看: