模式有两种形式:可反驳的(refutable)与不可反驳的(irrefutable)。可以配对任何可能数值的模式属于不可反驳的(irrefutable)。而可能会对某些数值配对失败的模式则属于可反驳的(refutable)。函式参数、let 陈述式与 for 循环只能接受不可反驳的模式,当数值无法配对时,程式无法作出任何有意义的事。if let 与 while let 表达式接受可反驳与不可反驳的模式,但是编译器会警告不可反驳的模式,因为定义上来说它们用来处理可能会失败的场合,条件表达式的功能就是依据成功或失败来执行不同动作。

大致上来说,你通常不需要担心可反驳与不可反驳模式之间的区别,不过你会需要熟悉可反驳性这样的概念,所以当你看到错误讯息时,能及时反应理解。在这样的场合,你需要依据程式码的预期行为来改变模式或是使用模式的结构。

让我们看看当我们尝试在 Rust 要求不可反驳模式的地方使用可反驳模式的范例与其反例。范例 18-8 显示了一个 let 陈述式,但是我们指定的模式是 Some(x),这是可反驳模式。如我们所预期的,此程式码无法编译。

如果 some_option_value 是数值 None,它会无法与模式 Some(x) 做配对,这意味着此模式是可反驳的。但是 let 陈述式只能接受不可反驳的模式,因为 程式码对 None 数值就无法作出任何有效的动作。在编译时 Rust 就会抱怨我们尝试在需要不可反驳模式的地方使用了可反驳模式:

note: `Option` defined here

因为 Some(x) 模式没有涵盖(且也涵盖不了!)所有有效的数值,Rust 合理地产生了编译错误。

如果我们在需要不可反驳模式的地方使用可反驳模式的错误,我们可以变更程式码使用模式的方式来修正:与其使用 let,我们可以改用 if let。这样如果模式不符的话,程式码就会跳过大括号中的程式码,让我们可以继续有效执行下去。范例 18-9 显示了如何修正范例 18-8 的程式码。

我们给了程式码出路!此程式码可以完美执行,虽然这也代表我们使用不可反驳模式的话会得到一些警告。基于此原因,match 的分支必须是可反驳模式。除了最后一个分支因为要配对任何剩余数值,所以会是不可反驳模式。Rust 允许我们在 match 只使用一个不可反驳模式的分支,不过这样做并不是很实用,且可以直接用简单的 let 陈述式取代。

现在你知道哪里能使用模式,以及可反驳与不可反驳模式的不同了。让我们来涵盖模式建立时可以使用的所有语法吧。