如果我尝试构建以下代码:
fn main () {
let my_val: u32 = 42;
match my_val % 2 {
0 => println!("We're even now"),
1 => println!("Well, that's odd"),
}
}
我会收到以下错误信息:
error[E0004]: non-exhaustive patterns: `2_u32..=u32::MAX` not covered
--> src/main.rs:4:11
|
4 | match my_val % 2 {
| ^^^^^^^^^^ pattern `2_u32..=u32::MAX` not covered
|
= note: the matched value is of type `u32`
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
|
6 ~ 1 => println!("Well, that's odd"),
7 ~ 2_u32..=u32::MAX => todo!(),
|
我不太明白。 代表什么情况2_u32..=u32::MAX
?
这真的很简单。
%
运算符使用特征定义std::ops::Rem
。其关联类型Output
定义该操作的结果。在实现中u32
Output
是u32
。因此从类型系统的角度来看Rem::rem
可以返回任何u32
值。因此,要使匹配详尽无遗,您必须匹配所有值。您可以使用
unreachable
宏(如果达到该宏,将在运行时产生恐慌)来表明这些路径是无法到达的。请注意,这个第三个分支很容易优化,并且编译器将在发布版本中执行此操作。您可以使用goldbolt检查生成的 ASM 。
如果您想知道,为什么我必须这样做,或者为什么 Rust 不能让我通过这一次,请注意,这是 Rust 期望明确性的一般哲学的一个例子。提到其他分支无法访问将导致没有或可忽略的运行时成本(如果您真的需要,您总是可以进入不安全
mod 3
领域),并且可以捕获可能的未来错误。例如,如果您开始使用而不是mod 2
算术,或者您从某个外部的、未经验证的来源传递这个值,那么您的代码仍然会编译,但这个错误将在运行时被捕获。