可以使用所有 Places 模式
Patterns 在 Rust 中的许多地方都出现了,你已经经常使用它们了 不知不觉中!本节讨论模式所在的所有位置 有效。
火柴
武器
正如第 6 章所讨论的,我们在表达式的臂中使用模式。
正式地,表达式被定义为关键字 ,一个值为
match on,以及一个或多个由 pattern 和
表达式,如果值与该 Arm 的模式匹配,则运行,如下所示:match
match
match
match VALUE {
PATTERN => EXPRESSION,
PATTERN => EXPRESSION,
PATTERN => EXPRESSION,
}
例如,下面是示例 6-5 中匹配变量中的值的表达式:match
Option<i32>
x
match x {
None => None,
Some(i) => Some(i + 1),
}
此表达式中的模式是 和 上的
每个箭头的左侧。match
None
Some(i)
表达式的一个要求是它们需要详尽无遗
表示表达式中值的所有可能性都必须
被考虑。确保您已涵盖所有可能性的一种方法是拥有
最后一个分支的 catchAll 模式:例如,与任何
value 永远不会失败,因此涵盖了所有剩余的情况。match
match
特定模式将匹配任何内容,但它永远不会绑定到
variable,因此它经常用于 last match 臂。模式可以是
例如,当您想要忽略任何未指定的值时很有用。我们将
在“忽略 a 中的值”中更详细地介绍了该模式
Pattern“ 部分
章。_
_
_
条件 if let
表达式
在第 6 章中,我们讨论了如何主要将表达式用作 shorter
编写仅匹配一个 case 的 a 的等效方法。
(可选)如果
中的模式不匹配。if let
match
if let
else
if let
示例 18-1 显示了也可以混合和匹配 、 和 表达式。这样做为我们提供了比表达式更大的灵活性,在表达式中,我们只能表示一个值来与
模式。此外,Rust 不要求一系列 , , 臂中的条件彼此相关。if let
else if
else if let
match
if let
else if
else if let
示例 18-1 中的代码决定了背景的颜色 针对多个条件的一系列检查。在此示例中,我们创建了 具有实际程序可能从用户那里接收的硬编码值的变量 输入。
文件名: src/main.rs
fn main() { let favorite_color: Option<&str> = None; let is_tuesday = false; let age: Result<u8, _> = "34".parse(); if let Some(color) = favorite_color { println!("Using your favorite color, {color}, as the background"); } else if is_tuesday { println!("Tuesday is green day!"); } else if let Ok(age) = age { if age > 30 { println!("Using purple as the background color"); } else { println!("Using orange as the background color"); } } else { println!("Using blue as the background color"); } }
如果用户指定了最喜欢的颜色,则该颜色将用作背景。 如果未指定收藏夹颜色,并且今天是星期二,则背景色为 绿。否则,如果用户将他们的年龄指定为字符串,并且我们可以解析 它成功作为一个数字,颜色是紫色或橙色,具体取决于 数字的值。如果这些条件都不适用,则背景 颜色是蓝色。
这种条件结构使我们能够支持复杂的需求。使用
hardcoded values 的 hardcoded 值,此示例将打印 .Using purple as the background color
你可以看到,它也可以以同样的方式引入阴影变量
that arms can: 该系列引入了一个新的
shadowed 变量,其中包含 Variant 内的值。这
意味着我们需要将条件放在该块中:我们不能
将这两个条件合并到 中。这
shadowed 的 30 在新的范围开始之前无效
带大括号。if let
match
if let Ok(age) = age
age
Ok
if age > 30
if let Ok(age) = age && age > 30
age
using 表达式的缺点是编译器不会检查
for exhaustiveness,而 with expressions 则如此。如果我们省略了
last 块,因此错过了处理某些情况,编译器将
不会提醒我们可能的 logic 错误。if let
match
else
while let
条件循环
在构造上与 类似,条件循环允许循环在模式继续匹配时运行。在列表中
18-2 我们编写一个循环,使用向量作为堆栈并打印
值,其推送顺序与它们被推送的顺序相反。if let
while let
while
while let
fn main() { let mut stack = Vec::new(); stack.push(1); stack.push(2); stack.push(3); while let Some(top) = stack.pop() { println!("{top}"); } }
此示例打印 3、2 和 1。该方法采用最后一个元素
从 vector 中传出并返回 。如果向量为空,则返回 。循环继续运行其块中的代码,因为
只要返回 .当返回 时,循环停止。我们可以
用于将每个元素从堆栈中弹出。pop
Some(value)
pop
None
while
pop
Some
pop
None
while let
为
循环
在循环中,关键字后面的值为
模式。例如,in the is the 模式。示例 18-3
演示如何在循环中使用模式来解构或断开
apart,一个 Tuples 作为循环的一部分。for
for
for x in y
x
for
for
fn main() { let v = vec!['a', 'b', 'c']; for (index, value) in v.iter().enumerate() { println!("{value} is at index {index}"); } }
示例 18-3 中的代码将打印以下内容:
$ cargo run
Compiling patterns v0.1.0 (file:///projects/patterns)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.52s
Running `target/debug/patterns`
a is at index 0
b is at index 1
c is at index 2
我们使用该方法调整迭代器,使其生成一个值
该值的索引,放置在 Tuples 中。生成的第一个值是
元。当此值与 pattern 匹配时,将是 和 将是 ,打印
输出。enumerate
(0, 'a')
(index, value)
index
0
value
'a'
让
语句
在本章之前,我们只明确讨论了使用 和 的模式,但实际上,我们也在其他地方使用了模式。
包括在声明中。例如,考虑一下这个简单的
变量赋值 :match
if let
let
let
#![allow(unused)] fn main() { let x = 5; }
每次你使用这样的语句时,你都在使用 patterns,
尽管您可能没有意识到!更正式地说,声明看起来
喜欢这个:let
let
let PATTERN = EXPRESSION;
在语句中,例如在 slot 中使用变量名称,
变量名称只是模式的一种特别简单的形式。Rust 比较
表达式,并为其找到的任何名称分配。所以在这个例子中,是一个模式,表示 “bind what matches here to
变量 .因为 name 是整个模式,所以这个模式
实际上意味着 “将所有内容绑定到变量 ,无论值是什么”。let x = 5;
PATTERN
let x = 5;
x
x
x
x
要更清楚地看到 的模式匹配方面,请考虑 清单
18-4 中,它使用 pattern with 来解构 Tuples。let
let
fn main() { let (x, y, z) = (1, 2, 3); }
在这里,我们将元组与模式进行匹配。Rust 将该值与模式进行比较,并发现该值与模式匹配,因此 Rust
绑定到 、 和 。你可以考虑这个元组
pattern 嵌套三个单独的可变 pattern。(1, 2, 3)
(x, y, z)
1
x
2
y
3
z
如果模式中的元素数与元素数不匹配 在 Tuples 中,整体类型不匹配,我们将收到 Compiler 错误。为 例如,示例 18-5 展示了一个尝试用 3 个 元素转换为两个变量,这不起作用。
fn main() {
let (x, y) = (1, 2, 3);
}
尝试编译此代码会导致以下类型错误:
$ cargo run
Compiling patterns v0.1.0 (file:///projects/patterns)
error[E0308]: mismatched types
--> src/main.rs:2:9
|
2 | let (x, y) = (1, 2, 3);
| ^^^^^^ --------- this expression has type `({integer}, {integer}, {integer})`
| |
| expected a tuple with 3 elements, found one with 2 elements
|
= note: expected tuple `({integer}, {integer}, {integer})`
found tuple `(_, _)`
For more information about this error, try `rustc --explain E0308`.
error: could not compile `patterns` (bin "patterns") due to 1 previous error
为了修复这个错误,我们可以使用 or 忽略元组中的一个或多个值,正如你将在“忽略
Pattern“部分。如果问题
是我们在 pattern 中有太多的变量,解决方案是让
类型通过删除变量进行匹配,使变量的数量等于数字
元组中的元素。_
..
功能参数
函数参数也可以是模式。示例 18-6 中的代码,其中
声明一个名为 的函数,该函数接受一个名为 类型的参数 ,现在看起来应该很熟悉。foo
x
i32
fn foo(x: i32) { // code goes here } fn main() {}
部分是花纹!就像我们对 所做的那样,我们可以在
函数的参数传递给模式。示例 18-7 将值拆分为一个 Tuples
当我们将其传递给函数时。x
let
文件名: src/main.rs
fn print_coordinates(&(x, y): &(i32, i32)) { println!("Current location: ({x}, {y})"); } fn main() { let point = (3, 5); print_coordinates(&point); }
此代码打印 .值与
pattern ,值 也是 ,值 是 。Current location: (3, 5)
&(3, 5)
&(x, y)
x
3
y
5
我们也可以像 function parameter lists 的 API API 中,因为闭包类似于函数,因为 在第 13 章中讨论。
此时,您已经看到了几种使用 patterns 的方法,但 patterns 没有 在我们可以使用它们的每个地方都以相同的方式工作。在某些地方,模式必须 无可辩驳;在其他情况下,它们可以被反驳。我们将讨论 接下来是这两个概念。
本文档由官方文档翻译而来,如有差异请以官方英文文档(https://doc.rust-lang.org/)为准