为什么匹配表达式不会先于其他手臂报告一个包罗万象的手臂 (_) 的错误?

Why does a match expression not report an error for a catch-all arm (_) prior to other arms?

Rust 有一个名为 match 的结构,它看起来与其他语言中的 switch 非常相似。但是我观察到 match.

的一种非常奇特的行为
let some_u32_value = 3;
match some_u32_value {
    _ => (),
    3 => println!("three"),
}

match 遵循提到 cases/patterns 的顺序。为什么默认(_)的case在最上面不报错呢?不过它确实给出了警告:

warning: unreachable pattern
 --> src/main.rs:5:9
  |
5 |         3 => println!("three"),
  |         ^
  |
  = note: #[warn(unreachable_patterns)] on by default

开关 Java 中的类似结构不保留任何顺序,因此在其他情况之前使用 default 不是错误(忽略掉落行为)。

int x = 0;

switch (x) {
  default:
    System.out.println("default");
    break;
  case 0:
      System.out.println("Zero");
} 

明确地这样做有什么目的吗?

无法访问的模式严格来说不是错误,我的意思是:它不会阻止编译器 "understanding" 代码,也不会使代码不安全。

类似地,例如,在 C 中,您可以 return 引用局部变量而不会触发错误(至少在 gcc 中):

#include <stdio.h>

int* foo() {
    int x = 0;

    return &x;
}

int main() {
    printf("%d", *foo());

    return 0;
}

通常,您不应将警告视为 "oh, that's only a warning, I don't care"。警告是编译器给出的实际有用的advice/information。

我喜欢中给出的定义:

A warning is often issued on recognizing a potential high-risk situation, a probable misunderstanding, degraded service or imminent failure.

因为它有助于理解错误和警告之间的区别:

  • 一个错误一个错误,
  • 警告是 potential/probable 错误或有问题的事情。

在这种情况下,match 的最后一个分支是一些死代码,因此编译器会相应地报告它。

Rust 的 match 表达式比 Java switch 语句强大得多,你可以做的不仅仅是匹配数字。

特别是,它支持模式匹配,可让您根据数据的结构或包含的值匹配数据片段。当您要匹配更复杂的模式时,能够指定顺序很重要,因为模式可能会重叠。例如:

let value = Some((Some(3), "hello"));

let s = match value {
    None => "Nothing there!".to_owned(),
    Some((Some(3), _)) => "The number is exactly 3!".to_owned(),
    Some((Some(n), _)) if n > 3 => format!("Got a number bigger than 3: {}", n),
    Some((None, msg)) => format!("Message with no number: {}", msg),
    Some((_, msg)) => format!("Got the message, ignore the rest: {}", msg),
    _ => "Anything else?".to_owned()
};

println!("result = {}", s);

这里的最后一个案例实际上是不可能的,因为其他分支涵盖了一切。如果这不是您想要的,编译器会发出警告。