可以使用所有 Places 模式

Patterns 在 Rust 中的许多地方都出现了,你已经经常使用它们了 不知不觉中!本节讨论模式所在的所有位置 有效。

match武器

如第 6 章所述,我们在match表达 式。 正式match表达式定义为关键字match,将值设置为 match on,以及一个或多个由 pattern 和 表达式,如果值与该 Arm 的模式匹配,则运行,如下所示:

match VALUE {
    PATTERN => EXPRESSION,
    PATTERN => EXPRESSION,
    PATTERN => EXPRESSION,
}

例如,下面是match表达式,它与Option<i32>value 在变量中x:

match x {
    None => None,
    Some(i) => Some(i + 1),
}

matchexpression 是NoneSome(i)在 每个箭头的左侧。

一个要求matchexpressions 的 API 表达式中,它们需要在 感觉match表达式必须 被考虑。确保您已涵盖所有可能性的一种方法是拥有 最后一个分支的 catchAll 模式:例如,与任何 value 永远不会失败,因此涵盖了所有剩余的情况。

特定模式将匹配任何内容,但它永远不会绑定到 variable,因此它经常用于 last match 臂。模式可以是 例如,当您想要忽略任何未指定的值时很有用。我们将 在“忽略 a 中的值”中更详细地介绍了该模式 Pattern“ 部分 章。___

有條件的if let表达 式

在第 6 章中,我们讨论了如何使用if let表达主要作为较短的 编写match这只匹配一个 case。 选择if let可以具有相应的else包含要运行的代码 的if let不匹配。

示例 18-1 表明也可以混合和匹配if let,else ifelse if let表达 式。这样做比match表达式中,我们只能表示一个值来与 模式。此外,Rust 并不要求一系列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");
    }
}

示例 18-1:混合if let,else if,else if let, 和else

如果用户指定了最喜欢的颜色,则该颜色将用作背景。 如果未指定收藏夹颜色,并且今天是星期二,则背景色为 绿。否则,如果用户将他们的年龄指定为字符串,并且我们可以解析 它成功作为一个数字,颜色是紫色或橙色,具体取决于 数字的值。如果这些条件都不适用,则背景 颜色是蓝色。

这种条件结构使我们能够支持复杂的需求。使用 hardcoded values 的 hardcoded 值,此示例将打印Using purple as the background color.

你可以看到if let也可以以相同的方式引入隐藏变量 那match武器罐:LINEif let Ok(age) = age引入了一个新的 阴影age变量,其中包含Ok变体。这 意味着我们需要将if age > 30condition 的 SET 中:我们不能 将这两个条件合并为if let Ok(age) = age && age > 30.这 阴影ageWe Want to compare to 30 在新范围开始之前无效 带大括号。

使用if letexpressions 是编译器不检查 for exhaustiveness,而使用match表达式。如果我们省略了 最后else块,因此错过了处理某些情况,编译器将 不会提醒我们可能的 logic 错误。

while let条件循环

在结构上类似于if letwhile let条件循环允许while循环运行。在列表中 18-2 我们编写一个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}");
    }
}

示例 18-2:使用while let循环打印值 只要stack.pop()返回Some

此示例打印 3、2 和 1。这popmethod 采用最后一个元素 out 并返回Some(value).如果 vector 为空,则pop返回None.这while循环继续运行其块中的代码,因为 只要pop返回Some.什么时候pop返回None,则循环停止。我们可以 用while let将每个元素从堆栈中弹出。

for循环

forloop 的值,该值紧跟在关键字for是一个 模式。例如,在for x in yx是模式。示例 18-3 演示如何在forloop 进行解构,或 break apart,一个元组作为for圈。

fn main() {
    let v = vec!['a', 'b', 'c'];

    for (index, value) in v.iter().enumerate() {
        println!("{value} is at index {index}");
    }
}

示例 18-3:在forloop 设置为 解构元组

示例 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

我们使用enumerate方法,因此它会生成一个值,而 该值的索引,放置在 Tuples 中。生成的第一个值是 元(0, 'a').当此值与模式匹配时(index, value),index将是0value将是'a',打印 输出。

let语句

在本章之前,我们只明确讨论了使用matchif let,但实际上,我们在其他地方也使用了 pattern, 包括let语句。例如,考虑一下这个简单的 变量赋值let:

#![allow(unused)]
fn main() {
let x = 5;
}

每次您使用let语句,就像这样,你一直在使用 patterns, 尽管您可能没有意识到!更正式地说,一个let声明外观 喜欢这个:

let PATTERN = EXPRESSION;

在像let x = 5;PATTERNslot 中, 变量名称只是模式的一种特别简单的形式。Rust 比较 表达式,并为其找到的任何名称分配。因此,在let x = 5;x是一种模式,表示“将此处匹配的内容绑定到 变量x.”因为x是整个模式,这个模式 实际上意味着 “将所有内容绑定到变量x,无论价值是多少。

要查看 的模式匹配方面let更明确地说,考虑列出 18-4 中,它使用带有let来解构一个元组。

fn main() {
    let (x, y, z) = (1, 2, 3);
}

示例 18-4:使用模式解构元组和 一次创建三个变量

在这里,我们将元组与模式进行匹配。Rust 比较了(1, 2, 3)到模式(x, y, z)并看到该值与模式匹配,因此 Rust 绑定1x,2y3z.你可以考虑这个元组 pattern 嵌套三个单独的可变 pattern。

如果模式中的元素数与元素数不匹配 在 Tuples 中,整体类型不匹配,我们将收到 Compiler 错误。为 例如,示例 18-5 展示了一个尝试用 3 个 元素转换为两个变量,这不起作用。

fn main() {
    let (x, y) = (1, 2, 3);
}

示例 18-5:错误地构造一个 变量与元组中的元素数不匹配

尝试编译此代码会导致以下类型错误:

$ 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

要修复此错误,我们可以使用 或_..,如您在 Pattern“部分。如果问题 是我们在 pattern 中有太多的变量,解决方案是让 类型通过删除变量进行匹配,使变量的数量等于数字 元组中的元素。

功能参数

函数参数也可以是模式。示例 18-6 中的代码,其中 声明一个名为foo它接受一个名为x的类型i32现在应该看起来很熟悉。

fn foo(x: i32) {
    // code goes here
}

fn main() {}

示例 18-6:函数签名使用 参数

x部分是图案!正如我们对let中,我们可以匹配 函数的参数传递给模式。示例 18-7 将值拆分为一个 Tuples 当我们将其传递给函数时。

文件名: src/main.rs

fn print_coordinates(&(x, y): &(i32, i32)) {
    println!("Current location: ({x}, {y})");
}

fn main() {
    let point = (3, 5);
    print_coordinates(&point);
}

示例 18-7:一个带有解构参数的函数 一个元组

此代码打印Current location: (3, 5).值&(3, 5)匹配 模式&(x, y)所以x是值3y是值5.

我们也可以像 function parameter lists 的 API API 中,因为闭包类似于函数,因为 在第 13 章中讨论。

此时,您已经看到了几种使用 patterns 的方法,但 patterns 没有 在我们可以使用它们的每个地方都以相同的方式工作。在某些地方,模式必须 无可辩驳;在其他情况下,它们可以被反驳。我们将讨论 接下来是这两个概念。

本文档由官方文档翻译而来,如有差异请以官方英文文档(https://doc.rust-lang.org/)为准