首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >18-Rust 教程 - 模式匹配进阶

18-Rust 教程 - 模式匹配进阶

作者头像
LarryLan
发布2026-05-14 18:09:41
发布2026-05-14 18:09:41
800
举报

模式匹配进阶

解构的艺术:把数据拆得明明白白

🎬 引入

还记得你第一次用 match 的时候吗?大概是这样:

代码语言:javascript
复制
let x = Some();

match x {
    Some(n) => println!("有值:{}", n),
    None => println!("没值"),
}

是不是觉得……也就这样?

兄弟,那你可太小看 Rust 的模式匹配了!它不仅能匹配值,还能解构数据、守卫条件、嵌套匹配。今天咱们就聊聊这个让代码像诗歌一样优雅的神器。

📌 核心概念

什么是模式?

模式是 Rust 中一种匹配值结构的方式。它告诉你:"如果数据长这样,就那样处理"。

生活化类比:

想象你去邮局寄包裹:

  • 简单匹配:看包裹大小(大/中/小)
  • 模式匹配:打开包裹看里面是什么(书?衣服?易碎品?),然后决定怎么包装

模式的种类

模式类型

示例

用途

字面量

0, true, "hello"

匹配具体值

变量

x, name

绑定到新变量

通配符

_

匹配任何值,不绑定

解构

Some(x), (a, b)

拆开复合类型

守卫

n if n > 0

添加额外条件

范围

1..=10

匹配范围内的值

引用

&x, &mut x

匹配引用

💻 代码示例

基础示例:解构元组

代码语言:javascript
复制
fn main() {
    let point = (, );
    
    // 解构元组
    let (x, y) = point;
    
    println!("x = {}, y = {}", x, y);  // x = 3, y = 5
}

看到没?一行代码就把元组拆开了!

解构结构体

代码语言:javascript
复制
struct Person {
    name: String,
    age: u32,
    city: String,
}

fn main() {
    let person = Person {
        name: String::from("Alice"),
        age: ,
        city: String::from("Beijing"),
    };
    
    // 解构结构体
    let Person { name, age, city } = person;
    
    println!("{} 今年 {} 岁,住在 {}", name, age, city);
    
    // 只解构部分字段
    let person2 = Person {
        name: String::from("Bob"),
        age: ,
        city: String::from("Shanghai"),
    };
    
    let Person { name, .. } = person2;  // .. 表示忽略其他字段
    println!("名字:{}", name);
}

说人话:

  • { name, age, city }:把三个字段都拆出来,变量名和字段名一样
  • { name, .. }:只拆 name,其他不要了

解构枚举

代码语言:javascript
复制
enum Message {
    Quit,
    Move { x: i32, y: i32 },
    Write(String),
    ChangeColor(i32, i32, i32),
}

fn main() {
    let msg = Message::Write(String::from("Hello"));
    
    match msg {
        Message::Quit => println!("退出"),
        Message::Move { x, y } => println!("移动到 ({}, {})", x, y),
        Message::Write(text) => println!("消息:{}", text),
        Message::ChangeColor(r, g, b) => println!("颜色:RGB({}, {}, {})", r, g, b),
    }
}

看到没?枚举的每个变体都可以解构出里面的数据!

模式守卫(if 守卫)

代码语言:javascript
复制
fn main() {
    let num = Some();
    
    match num {
        Some(x) if x <  => println!("小于 5:{}", x),
        Some(x) => println!("大于等于 5:{}", x),
        None => println!("没有值"),
    }
}

说人话:

if x < 5 就是守卫——即使匹配了 Some(x),还要通过守卫的检查才行。

多重模式(| 运算符)

代码语言:javascript
复制
fn main() {
    let x = ;
    
    match x {
         |  |  => println!("1 到 3"),
         |  |  => println!("4 到 6"),
        _ => println!("其他"),
    }
}

| 相当于"或"——匹配 1、2、3 中的任何一个都行。

范围模式(..= 运算符)

代码语言:javascript
复制
fn main() {
    let age = ;
    
    match age {
        ..= => println!("儿童"),
        ..= => println!("青少年"),
        ..= => println!("成年人"),
        ..= => println!("老年人"),  // 60 及以上
    }
}

注意: ..= 是闭区间(包含两端),.. 是开区间(不包含右端)。

嵌套模式

代码语言:javascript
复制
struct Point {
    x: i32,
    y: i32,
}

enum Direction {
    Up,
    Down,
    Left,
    Right,
}

fn main() {
    let data = (Point { x: , y:  }, Direction::Up);
    
    match data {
        (Point { x: , y:  }, _) => println!("原点,方向无所谓"),
        (Point { x, y }, Direction::Up) => println!("向上,位置 ({}, {})", x, y),
        (Point { x, y }, Direction::Down) => println!("向下,位置 ({}, {})", x, y),
        _ => println!("其他情况"),
    }
}

看到没?模式可以嵌套——元组里套结构体,结构体里套枚举,想多深就多深!

@ 绑定符(既匹配又绑定)

代码语言:javascript
复制
fn main() {
    let num = Some();
    
    match num {
        Some(n @ ..=) => println!("1 到 10 之间的数:{}", n),
        Some(n) => println!("其他数:{}", n),
        None => println!("没有值"),
    }
}

说人话:

n @ 1..=10 的意思是:匹配 1 到 10 的范围,同时把这个值绑定到变量 n 上。

解构引用

代码语言:javascript
复制
fn main() {
    let x = ;
    let ref_x = &x;
    
    match ref_x {
        &val => println!("值是:{}", val),
    }
    
    // 或者用 ref 关键字
    let y = Some(String::from("hello"));
    match y {
        Some(ref s) => println!("字符串:{}", s),  // s 是 &String
        None => println!("没有值"),
    }
}

注意:

  • &val:匹配引用,解引用
  • ref s:匹配值,但绑定为引用

🐛 常见坑点

坑点 1:不 exhaustive 的匹配

代码语言:javascript
复制
fn main() {
    let x = Some();
    
    // ❌ 编译错误
    match x {
        Some(n) => println!("有值:{}", n),
        // 忘了处理 None!
    }
}

编译器在说什么人话?

"你漏了 None 的情况!Rust 要求你处理所有可能。"

解决方案:

代码语言:javascript
复制
match x {
    Some(n) => println!("有值:{}", n),
    None => println!("没值"),
}

或者用 _ 兜底:

代码语言:javascript
复制
match x {
    Some(n) => println!("有值:{}", n),
    _ => println!("其他情况"),
}

坑点 2:守卫的优先级

代码语言:javascript
复制
fn main() {
    let num = Some();
    
    // ❌ 这样写有问题
    match num {
        Some(x) => println!("任何 Some"),
        Some(x) if x >  => println!("大于 10"),  // 永远到不了这里!
        _ => println!("其他"),
    }
}

问题: 第一个 Some(x) 已经匹配了所有 Some,后面的守卫永远不会执行。

正确写法:

代码语言:javascript
复制
match num {
    Some(x) if x >  => println!("大于 10"),
    Some(x) => println!("其他 Some"),
    _ => println!("其他"),
}

记住: 守卫条件要放在前面!

坑点 3:解构时忘记移动

代码语言:javascript
复制
fn main() {
    let s = String::from("hello");
    let opt = Some(s);
    
    // ❌ 这样写会移动 s
    match opt {
        Some(inner) => println!("{}", inner),  // s 被移动了
        None => (),
    }
    
    // println!("{}", s);  // ❌ 编译错误:s 已被移动
}

解决方案:

代码语言:javascript
复制
match &opt {
    Some(inner) => println!("{}", inner),  // 借用,不移动
    None => (),
}

坑点 4:ref 和 & 搞混

代码语言:javascript
复制
fn main() {
    let s = String::from("hello");
    let opt = Some(s);
    
    // 正确理解:
    match opt {
        Some(ref inner) => {
            // inner 的类型是 &String(借用)
            println!("{}", inner);
        },
        None => (),
    }
    
    // opt 还可以用,因为只是借用
    println!("{:?}", opt);
}

记住:

  • &inner:匹配引用,inner 是值
  • ref inner:匹配值,inner 是引用

🎯 实战案例

案例 1:解析配置

代码语言:javascript
复制
enum ConfigValue {
    String(String),
    Number(i32),
    Boolean(bool),
    List(Vec<ConfigValue>),
}

fn print_config(key: &str, value: &ConfigValue) {
    match value {
        ConfigValue::String(s) => println!("{} = \"{}\"", key, s),
        ConfigValue::Number(n) => println!("{} = {}", key, n),
        ConfigValue::Boolean(b) => println!("{} = {}", key, if *b { "true" } else { "false" }),
        ConfigValue::List(items) => {
            println!("{} = [", key);
            for item in items {
                print_config("  ", item);
            }
            println!("]");
        }
    }
}

fn main() {
    let config = ConfigValue::List(vec![
        ConfigValue::String(String::from("host")),
        ConfigValue::Number(),
        ConfigValue::Boolean(true),
    ]);
    
    print_config("config", &config);
}

案例 2:状态机

代码语言:javascript
复制
enum OrderState {
    Created,
    Paid { amount: f64 },
    Shipped { tracking: String },
    Delivered,
    Cancelled { reason: String },
}

fn handle_order(state: OrderState) {
    match state {
        OrderState::Created => {
            println!("订单已创建,等待付款");
        }
        OrderState::Paid { amount } => {
            println!("已付款 {:.2} 元,准备发货", amount);
        }
        OrderState::Shipped { tracking } => {
            println!("已发货,单号:{}", tracking);
        }
        OrderState::Delivered => {
            println!("已送达,感谢购买!");
        }
        OrderState::Cancelled { reason } => {
            println!("订单已取消:{}", reason);
        }
    }
}

fn main() {
    let order = OrderState::Paid { amount: 99.99 };
    handle_order(order);
}

案例 3:复杂数据解构

代码语言:javascript
复制
#[derive(Debug)]
struct User {
    id: u32,
    name: String,
    role: Role,
}

#[derive(Debug)]
enum Role {
    Admin,
    User { permissions: Vec<String> },
    Guest,
}

fn check_access(user: User) {
    match user {
        User { role: Role::Admin, .. } => {
            println!("管理员,拥有所有权限");
        }
        User { name, role: Role::User { permissions }, .. } => {
            println!("用户 {} 的权限:", name);
            for perm in permissions {
                println!("  - {}", perm);
            }
        }
        User { name, role: Role::Guest, .. } => {
            println!("访客 {},权限受限", name);
        }
    }
}

fn main() {
    let user = User {
        id: ,
        name: String::from("Alice"),
        role: Role::User {
            permissions: vec![
                String::from("read"),
                String::from("write"),
            ],
        },
    };
    
    check_access(user);
}

🧠 思维导图

18-模式匹配进阶
18-模式匹配进阶

📝 小结

金句回顾:

  1. 模式匹配不只是 match——let、函数参数都能用
  2. 解构是核心——把复杂数据拆开用
  3. 守卫加条件——if 让匹配更精确
  4. @ 绑定符——既匹配又绑定,一举两得
  5. exhaustive 检查——Rust 逼你处理所有情况

下篇预告:

咱们已经学了 Cargo 的基础用法(cargo newcargo buildcargo run),但那只是冰山一角。下篇深入聊聊包管理 Cargo,看看怎么管理依赖、配置项目、发布 crate,让你成为 Cargo 大师!

🔗 参考资料

  • Rust Book - 模式匹配
  • Pattern Syntax
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2026-05-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Larry的Hub 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 模式匹配进阶
    • 🎬 引入
    • 📌 核心概念
      • 什么是模式?
      • 模式的种类
    • 💻 代码示例
      • 基础示例:解构元组
      • 解构结构体
      • 解构枚举
      • 模式守卫(if 守卫)
      • 多重模式(| 运算符)
      • 范围模式(..= 运算符)
      • 嵌套模式
      • @ 绑定符(既匹配又绑定)
      • 解构引用
    • 🐛 常见坑点
      • 坑点 1:不 exhaustive 的匹配
      • 坑点 2:守卫的优先级
      • 坑点 3:解构时忘记移动
      • 坑点 4:ref 和 & 搞混
    • 🎯 实战案例
      • 案例 1:解析配置
      • 案例 2:状态机
      • 案例 3:复杂数据解构
    • 🧠 思维导图
    • 📝 小结
    • 🔗 参考资料
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档