当前位置: 首页 > article >正文

深入浅出 Rust 的强大 match 表达式

一、什么是 match

match 表达式能让你将一个值与一系列“模式”进行比较,并根据匹配到的模式执行相应的代码。常见的模式类型包括:

  • 字面量(例如 37"hello"
  • 枚举(Enum)变体(例如 Coin::Penny
  • 变量绑定(如在 Coin::Quarter(state) 中捕获 state
  • 通配符(_),用来匹配任何值
  • 其他更高级的模式(在 Rust 程序设计语言 第 19 章会有深入讲解)

从结构上看,可将 match 类比为一个“分类器”或“检索器”:

  1. 传入的值依次与每个模式进行匹配。
  2. 一旦找到匹配的模式,运行对应的代码,并返回结果。
  3. 如果没有匹配到,继续检查下一个模式。
  4. match 必须覆盖所有可能的值,也就是“穷尽匹配”。

二、示例:硬币分类

先来一个经典示例。假设我们有一个表示美国硬币的枚举 Coin

#[derive(Debug)]
enum UsState {
    Alaska,
    // ... 其他州
}

enum Coin {
    Penny,
    Nickel,
    Dime,
    Quarter(UsState),
}

如果要写一个函数 value_in_cents,返回某个硬币的美分值,就可以这样:

fn value_in_cents(coin: Coin) -> u8 {
    match coin {
        Coin::Penny => 1,
        Coin::Nickel => 5,
        Coin::Dime => 10,
        Coin::Quarter(state) => {
            println!("来自 {:?} 州的 25 美分硬币!", state);
            25
        }
    }
}

2.1 解析

  1. match coin:这里的 coin 就是要进行“模式匹配”的值。
  2. 匹配分支(arms):每一行(如 Coin::Penny => 1)被称为一个“匹配分支”或“分支模式”。
  3. 模式与代码Coin::Penny => 1 表示如果 coin 的值是 Coin::Penny,就返回 1。对于 Coin::Quarter(state),还会打印出所在州,并返回 25

Rust 会逐个检查 coin 与各个分支是否匹配,一旦匹配到就执行对应的代码并返回该结果。因为我们覆盖了 PennyNickelDimeQuarter 四种变体,所以 Rust 确定所有情况都被“穷尽”,编译通过。

三、绑定内部值

Coin::Quarter(state) 这个分支里,我们不仅仅匹配到 Quarter,还把这个硬币的具体“州”数据绑定到了变量 state 上,然后就能在分支中使用它,比如打印或做进一步处理。这种模式绑定(pattern binding)让我们可以优雅地解构枚举内部的数据。

四、与 Option<T> 搭配使用

在实际开发中,match 常被用来搭配 Option<T> 处理“有值”或“无值”的情形。示例:我们要写一个函数 plus_one,它接受 Option<i32>,如果里面有值就加一,如果没有值就原样返回 None

fn plus_one(x: Option<i32>) -> Option<i32> {
    match x {
        None => None,
        Some(i) => Some(i + 1),
    }
}

4.1 工作原理

  • 当传入 None 时,与分支 None => None 匹配,直接返回 None
  • 当传入 Some(i) 时,与分支 Some(i) => Some(i + 1) 匹配,此时 i 会绑定到内部的数字,然后执行 i + 1,最后返回新的 Some(i + 1)

借助枚举的严格穷尽性,Rust 强制要求我们显式处理 None,从而避免了“null 引用”带来的潜在错误。

五、穷尽匹配:覆盖所有可能分支

Rust 对 match 的“穷尽匹配”有严格要求:你必须确保所有可能情况都能被匹配到,否则编译器会报错提示遗漏了哪些情况。比如,我们如果在 plus_one 中遗漏了 None

fn plus_one_bug(x: Option<i32>) -> Option<i32> {
    match x {
        Some(i) => Some(i + 1),
    }
}

编译器就会报错,提醒你还没有处理 None。这项特性让我们在编译期就能暴露逻辑漏洞,大幅降低 bug 产生的概率。

六、通配模式 _

在有些场景下,我们只想对少数情况做特殊处理,所有其他情况统一处理。Rust 提供了 _ 来做“通配”匹配(也称“捕获所有剩余情况”)。例如:

fn dice_roll_outcome(roll: u8) {
    match roll {
        3 => fancy_hat(),
        7 => remove_hat(),
        _ => reroll(), // 其余的全部执行 reroll()
    }
}

fn fancy_hat() { /* ... */ }
fn remove_hat() { /* ... */ }
fn reroll() { /* ... */ }

这里 _ 可以匹配任何值,但不会将其绑定到变量中。如果你确实需要使用那个值,可以把 _ 换成一个命名变量(例如 other),这样就能在分支里使用了。

七、分支中的多行代码

大多数时候,每个匹配分支只返回一个简单值,不需要花括号。如果需要在分支中执行多行操作,可以使用花括号包起来,最后一行将作为返回值。例如:

fn value_in_cents(coin: Coin) -> u8 {
    match coin {
        Coin::Penny => {
            println!("幸运的便士!");
            1
        },
        Coin::Nickel => 5,
        Coin::Dime => 10,
        Coin::Quarter(state) => {
            println!("来自 {:?} 州的 25 美分硬币!", state);
            25
        },
    }
}

这里当匹配到 Coin::Penny 时,会先打印 “幸运的便士!”,然后返回 1

八、总结与收获

  1. 强大的模式匹配
    Rust 的模式匹配远不止简单的“值相等”。后续还可以学习更高级的模式,如解构结构体、元组、范围匹配、匹配守卫(guard)等。

  2. 穷尽性
    match 要求你必须处理所有可能情况,这在很大程度上减少了遗漏错误。

  3. Enum + match = 强力组合
    Enum 天生与 match 搭配;在模式中既能指定变体,又能访问内部数据。

  4. 通配模式 _
    _ 用于捕获其他未匹配的情况,避免写过多重复分支;若要使用未匹配的值,则使用命名变量替代 _

  5. 匹配分支的返回值
    匹配分支中的代码是一个表达式,match 的最终结果就是匹配分支所产生的值。

九、结语

Rust 的 match 表达式是编写安全、易读且可靠的代码的有力工具。它不仅迫使你在编译阶段考虑到所有可能的情况,而且还能让你专注于“要对每种情况如何处理”这一核心逻辑。很多 Rust 开发者在接触到这种枚举加模式匹配的风格后,纷纷表示“再也离不开了”。

如果你想进一步了解更多高级模式的细节(比如范围匹配、复杂数据结构的解构匹配等),可以阅读 The Rust Programming Language 第 19 章。相信随着对 match 越来越熟悉,你会发现它能让 Rust 代码既优雅又高效!

祝你匹配愉快,写出更多健壮且清晰的 Rust 代码!


http://www.kler.cn/a/522726.html

相关文章:

  • scratch学习教程
  • sunrays-framework配置重构
  • 【Elasticsearch】RestClient操作文档
  • JVM对象分配内存如何保证线程安全?
  • C#字典Dictionary用法详解
  • Canny 边缘检测
  • 怎么样把pdf转成图片模式(不能复制文字)
  • PyCharm介绍
  • 宝塔面板SSL加密访问设置教程
  • 自助设备系统设置——对接POS支付
  • 《程序人生》工作2年感悟
  • 蓝桥杯python语言基础(1)——编程基础
  • (2025 年最新)MacOS Redis Desktop Manager中文版下载,附详细图文
  • 【BQ3568HM开发板】如何在OpenHarmony上通过校园网的上网认证
  • USB鼠标的数据格式
  • React 封装高阶组件 做路由权限控制
  • 梯度下降优化算法-Adam
  • 【无标题】规范学生的课堂行为。
  • 指针的介绍2后
  • 【Rust自学】15.7. 循环引用导致内存泄漏
  • Spring AOP原理
  • 智能门锁开发系列:从设计到实现的全面解析
  • Mybaties缓存机制
  • 装饰SpringMVC的适配器实现响应自动包装
  • 每日一题 429. N 叉树的层序遍历
  • WebPages 表单:设计与实现指南