我们在之前的部分中使用 Option 时,是为了从 Some 中取出其内部的 T 值;我们还可以像处理Coin 枚举那样使用 match 处理 Option!只不过这回比较的不再是硬币,而是 Option 的成员,但 match 表达式的工作方式保持不变。
比如我们想要编写一个函数,它获取一个 Option ,如果其中含有一个值,将其加一。如果其中没有值,函数应该返回 None 值,而不尝试执行任何操作。
fn plus_one(x: Option<i32>) -> Option<i32> {
match x {
None => None,
Some(i) => Some(i + 1),
}
}
let five = Some(5);
let six = plus_one(five);
let none = plus_one(None);
# }
匹配 Some(T)
让我们更仔细地检查 plus_one 的第一行操作。当调用 plus_one(five) 时,plus_one 函数体中的 x 将会是值 Some(5)。接着将其与每个分支比较。
# fn plus_one(x: Option<i32>) -> Option<i32> {
# match x {
None => None,
# Some(i) => Some(i + 1),
# }
# }
#
# let five = Some(5);
# let six = plus_one(five);
# let none = plus_one(None);
# }
值 Some(5) 并不匹配模式 None,所以继续进行下一个分支。
# fn main() {
# fn plus_one(x: Option<i32>) -> Option<i32> {
# match x {
# None => None,
Some(i) => Some(i + 1),
# }
# }
#
# let five = Some(5);
# let six = plus_one(five);
# let none = plus_one(None);
# }
Some(5) 与 Some(i) 匹配吗?当然匹配!它们是相同的成员。i 绑定了 Some 中包含的值,所以 i 的值是 5。接着匹配分支的代码被执行,所以我们将 i 的值加一并返回一个含有值 6 的新 Some。
接着考虑下示例 6-5 中 plus_one 的第二个调用,这里 x 是 None。我们进入 match 并与第一个分支相比较。
# fn plus_one(x: Option<i32>) -> Option<i32> {
# match x {
None => None,
# Some(i) => Some(i + 1),
# }
# }
#
# let five = Some(5);
# let six = plus_one(five);
# let none = plus_one(None);
# }
匹配上了!这里没有值来加一,所以程序结束并返回 => 右侧的值 None,因为第一个分支就匹配到了,其他的分支将不再比较。
将 match 与枚举相结合在很多场景中都是有用的。你会在 Rust 代码中看到很多这样的模式:match 一个枚举,绑定其中的值到一个变量,接着根据其值执行代码。这在一开始有点复杂,不过一旦习惯了,你会希望所有语言都拥有它!这一直是用户的最爱。