3.8 KiB
Refutability(可反驳性): 模式是否会匹配失效
匹配模式有两种形式: refutable(可反驳)和irrefutable(不可反驳). 对任意可能的值进行匹配都不会失效的模式被称为是irrefutable(不可反驳)的, 而对某些可能的值进行匹配会失效的模式被称为是refutable(可反驳)的.
let
语句、 函数参数和for
循环被约束为只接受irrefutable模式, 因为如果模式匹配失效程序就不会正确运行. if let
和while let
表达式被约束为只接受refutable模式, 因为它们需要处理可能存在的匹配失效的情况, 并且如果模式匹配永不失效, 那它们就派不上用场了.
通常, 你不用关心refutable和irrefutable模式的区别, 当你看见它出现在了错误消息中时, 你只要了解可反驳性(refutability)的概念即可. 如果你得到一个涉及到可反驳性概念的错误消息, 根据你的代码行为的意图, 你只需改变匹配模式或者是改变你构造模式的方法即可.
让我们来看几个例子. 在本章的前面部分, 我们提到let x = 5;
. 这里x
就是一个我们被允许使用irrefutable的模式: 因为它不可能匹配失效. 相反, 如果用let
来匹配一个枚举的变体, 比如像例18-7中列出的那样从Option<T>
枚举中只匹配Some<T>
这个值:
let Some(x) = some_option_value;
例18-7: 试试用一个有let
的refutable模式
如果some_option_value
的值是None
, some_option_value
将不会匹配模式Some(x)
. 模式Some(x)
是可反驳的(refutable), 因为存在一个使它匹配失效的值. 如果some_option_value
的值是None
, 那么let
语句就不会产生任何效果. 因此Rust会在编译时会报期望irrefutable模式但是却得到了一个refutable模式的错误:
error[E0005]: refutable pattern in local binding: `None` not covered
--> <anon>:3:5
|
3 | let Some(x) = some_option_value;
| ^^^^^^^ pattern `None` not covered
因为我们没有(也不能)覆盖到模式Some(x)
的每一个可能的值, 所以Rust会报错.
如果我们采用refutable模式, 使用if let
而不是let
. 这样当模式不匹配时, 在花括号中的代码将不执行, 这段代码只有在值匹配模式的时候才会执行, 也只在此时有意义. Listing 18-8 shows how to fix the code in Listing 18-7 with Some(x)
matching some_option_value
. Using the refutable pattern Some(x)
is allowed,
since this example uses if let
:
# let some_option_value: Option<i32> = None;
if let Some(x) = some_option_value {
println!("{}", x);
}
Listing 18-8: Using if let
and a block with refutable
patterns instead of let
Consequently, if we give if let
an irrefutable pattern that will always match,
such as x
as shown in Listing 18-9:
if let x = 5 {
println!("{}", x);
};
Listing 18-9: Attempting to use an irrefutable pattern
with if let
Rust will complain that it doesn't make sense to use if let
with an
irrefutable pattern:
error[E0162]: irrefutable if-let pattern
--> <anon>:2:8
|
2 | if let x = 5 {
| ^ irrefutable pattern
Generally, match arms use refutable patterns, except for the last arm that
might match any remaining values with an irrefutable pattern. A match
with
only one arm whose pattern is irrefutable is allowed, but it's not particularly
useful and could be replaced with a simpler let
statement. Both the expressions
associated with a let
statement and a single arm irrefutable match will
unconditionally be run, so the end result is the same if their expressions are.
Now that we've discussed all the places that patterns can be used and the difference between refutable and irrefutable patterns, let's go over all the syntax we can use to create patterns.