Rust

2025年07月13日更新 6 人订阅
原价: ¥ 6 限时优惠
专栏简介 Rust编程语言之错误处理 Rust 语言之 flod Rust编程语言之Cargo、Crates.io详解 Rust编程语言之枚举与模式匹配 Rust语言 - 接口设计的建议之受约束(Constrained) Rust编程语言之无畏并发 Rust语言 - 接口设计的建议之灵活(flexible) Rust语言 - 接口设计的建议之显而易见(Obvious) Rust语言 - 接口设计的建议之不意外(unsurprising) Rust 实战:构建实用的 CLI 工具 HTTPie Rust编程语言学习之高级特性 Rust内存管理揭秘:深度剖析指针与智能指针 解决Rust中数组和切片的编译时大小问题 《Rust编程之道》学习笔记一 Rust Async 异步编程 简易教程 使用 Async Rust 构建简单的 P2P 节点 Rust编程语言入门之模式匹配 Rust async 编程 Rust编程语言之编写自动化测试 Rust编程语言之函数式语言特性:迭代器和闭包 《Rust编程之道》学习笔记二 Rust Tips 比较数值 使用 Rust 开发一个微型游戏 Rust编程初探:深入理解Struct结构体 深入理解Rust中的内存管理:栈、堆与静态内存详解 深入理解 Rust 结构体:经典结构体、元组结构体和单元结构体的实现 深入掌握 Rust 结构体:从模板到实例化的完整指南 深入理解Rust中的结构体:逻辑与数据结合的实战示例 深入理解 Rust 枚举:从基础到实践 掌握Rust字符串的精髓:String与&str的最佳实践 全面解析 Rust 模块系统:实战案例与应用技巧 Rust 中的 HashMap 实战指南:理解与优化技巧 掌握Rust模式匹配:从基础语法到实际应用 Rust 中的面向对象编程:特性与实现指南 深入理解 Rust 的 Pin 和 Unpin:理论与实践解析 Rust Trait 与 Go Interface:从设计到实战的深度对比 从零开始:用 Rust 和 Axum 打造高效 Web 应用 Rust 错误处理详解:掌握 anyhow、thiserror 和 snafu Rust 如何优雅实现冒泡排序 链表倒数 K 节点怎么删?Python/Go/Rust 实战 用 Rust 玩转数据存储:JSON 文件持久化实战 Rust实战:打造高效字符串分割函数 如何高效学习一门技术:从知到行的飞轮效应 Rust 编程入门:Struct 让代码更优雅 Rust 编程:零基础入门高性能开发 用 Rust 写个猜数游戏,编程小白也能上手! Rust 入门教程:变量到数据类型,轻松掌握! 深入浅出 Rust:函数、控制流与所有权核心特性解析 从零开始:用 Rust 和 Axum 打造高效 Web 服务 Rust 集合类型解析:Vector、String、HashMap 深入浅出Rust:泛型、Trait与生命周期的硬核指南 Rust实战:博物馆门票限流系统设计与实现 用 Rust 打造高性能图片处理服务器:从零开始实现类似 Thumbor 的功能 Rust 编程入门实战:从零开始抓取网页并转换为 Markdown 深入浅出 Rust:高效处理二进制数据的 Bytes 与 BytesMut 实战 Rust智能指针:解锁内存管理的进阶之道 用 Rust 打造命令行利器:从零到一实现 mini-grep 解锁Rust代码组织:轻松掌握Package、Crate与Module Rust 所有权:从内存管理到生产力释放 深入解析 Rust 的面向对象编程:特性、实现与设计模式 Rust + Protobuf:从零打造高效键值存储项目 bacon 点燃 Rust:比 cargo-watch 更爽的开发体验 用 Rust 打造微型游戏:从零开始的 Flappy Dragon 开发之旅 函数式编程的Rust之旅:闭包与迭代器的深入解析与实践 探索Rust编程之道:从设计哲学到内存安全的学习笔记 精读《Rust编程之道》:吃透语言精要,彻底搞懂所有权与借用 Rust 避坑指南:搞定数值比较,别再让 0.1 + 0.2 != 0.3 困扰你! 告别 Vec!掌握 Rust bytes 库,解锁零拷贝的真正威力 告别竞态条件:基于 Axum 和 Serde 的 Rust 并发状态管理最佳实践 Rust 异步编程实践:从 Tokio 基础到阻塞任务处理模式 Rust 网络编程实战:用 Tokio 手写一个迷你 TCP 反向代理 (minginx) 保姆级教程:Zsh + Oh My Zsh 终极配置,让你的 Ubuntu 终端效率倍增 不止于后端:Rust 在 Web 开发中的崛起之路 (2024数据解读) Rust核心利器:枚举(Enum)与模式匹配(Match),告别空指针,写出优雅健壮的代码 Rust 错误处理终极指南:从 panic! 到 Result 的优雅之道 想用 Rust 开发游戏?这份超详细的入门教程请收好! 用 Rust 实现 HTTPie:一个现代 CLI 工具的构建过程

掌握Rust模式匹配:从基础语法到实际应用

掌握Rust模式匹配:从基础语法到实际应用本篇文章将探讨Rust编程语言中至关重要的特性之一——模式匹配。Rust语言的模式匹配功能强大,不仅能处理简单的值匹配,还能解构和操作复杂的数据结构。通过深入学习模式匹配,程序员可以更加高效地编写出清晰、简洁且易于维护的代码。Rust语言中的模式

掌握Rust模式匹配:从基础语法到实际应用

本篇文章将探讨 Rust 编程语言中至关重要的特性之一——模式匹配。Rust 语言的模式匹配功能强大,不仅能处理简单的值匹配,还能解构和操作复杂的数据结构。通过深入学习模式匹配,程序员可以更加高效地编写出清晰、简洁且易于维护的代码。

Rust 语言中的模式匹配是一种特殊的语法结构,用于匹配变量、解构数组、结构体、枚举和元组等。本文主要介绍了 Rust 中各种模式的使用场景,包括 match、if let、while let、for 循环以及函数参数。除了基础语法外,还讲解了可辩驳性和无可辩驳性、字面值匹配、命名变量、多重模式、范围匹配、结构解构等模式的使用细节。

模式

  • 模式是Rust中的一种特殊语法,用于匹配复杂和简单类型的结构
  • 将模式与匹配表达式和其他构造结合使用,可以更好地控制程序的控制流
  • 模式由以下元素(的一些组合)组成:
    • 字面值
    • 解构的数组、enum、struct 和 tuple
    • 变量
    • 通配符
    • 占位符
  • 想要使用模式,需要将其与某个值进行比较:
    • 如果模式匹配,就可以在代码中使用这个值的相应部分

一、用到模式(匹配)的地方

match 的 Arm

match VALUE {
  PATTERN => EXPRESSION,
  PATTERN => EXPRESSION,
  PATTERN => EXPRESSION,
}
  • match 表达式的要求:
    • 详尽(包含所有的可能性)
  • 一个特殊的模式:_(下划线):
    • 它会匹配任何东西
    • 不会绑定到变量
    • 通常用于 match 的最后一个 arm;或用于忽略某些值。

条件 if let 表达式

  • if let 表达式主要是作为一种简短的方式来等价的代替只有一个匹配项的 match
  • if let 可选的可以拥有 else,包括:
    • else if
    • else if let
  • 但,if let 不会检查穷尽性
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, {}, as the background", color);
  } else if if_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");
  }
}

While let 条件循环

  • 只要模式继续满足匹配的条件,那它允许 while 循环一直运行
fn main() {
  let mut stack = Vec::new();

  stack.push(1);
  stack.push(2);
  stack.push(3);

  while let Some(top) = stack.pop() {
    println!("{}", top);
  }
}

for 循环

  • for 循环是Rust 中最常见的循环
  • for 循环中,模式就是紧随 for 关键字后的值
fn main() {
  let v = vec!['a', 'b', 'c'];

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

Let 语句

  • let 语句也是模式
  • let PATTERN = EXPRESSION
fn main() {
  let a = 5;

  let (x, y, z) = (1, 2, 3);

  let (q, w) = (4, 5, 6); // 报错 类型不匹配 3 2
}

函数参数

  • 函数参数也可以是模式
fn foo(x: i32) {
  // code goes here
}

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

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

二、可辩驳性:模式是否会无法匹配

模式的两种形式

  • 模式有两种形式:可辨驳的、无可辩驳的
  • 能匹配任何可能传递的值的模式:无可辩驳的
    • 例如:let x = 5;
  • 对某些可能得值,无法进行匹配的模式:可辩驳的
    • 例如:if let Some(x) = a_value
  • 函数参数、let 语句、for 循环只接受无可辩驳的模式
  • if let 和 while let 接受可辨驳和无可辩驳的模式
fn main() {
  let a: Option<i32> = Some(5);
  let Some(x) = a: // 报错 None
  if let Some(x) = a {}
  if let x = 5 {} // 警告
}

三、模式语法

匹配字面值

  • 模式可直接匹配字面值
fn main() {
  let x = 1;

  match x {
    1 => println!("one"),
    2 => println!("two"),
    3 => println!("three"),
    _ => println!("anything"),
  }
}

匹配命名变量

  • 命名的变量是可匹配任何值的无可辩驳模式
fn main() {
  let x = Some(5);
  let y = 10;

  match x {
    Some(50) => println!("Got 50"),
    Some(y) => println!("Matched, y = {:?}", y),
    _ => println!("Default case, x = {:?}", x),
  }

  println!("at the end: x = {:?}, y = {:?}", x, y);
}

多重模式

  • 在match 表达式中,使用 | 语法(就是或的意思),可以匹配多种模式
fn main() {
  let x = 1;

  match x {
    1 | 2 => println!("one or two"),
    3 => println!("three"),
    _ => println!("anything"),
  }
}

使用 ..= 来匹配某个范围的值

fn main() {
  let x = 5;
  match x {
    1..=5 => println!("one through five"),
    _ => println!("something else"),
  }

  let x = 'c';
  match x {
    'a' ..='j' => println!("early ASCII letter"),
    'k' ..='z' => println!("late ASCII letter"),
    _ => println!("something else"),
  }
}

解构以分解值

  • 可以使用模式来解构 struct、enum、tuple,从而引用这些类型值的不同部分
struct Point {
  x: i32,
  y: i32,
}

fn main() {
  let p = Point { x: 0, y: 7 };

  let Point { x: a, y: b } = p;
  assert_eq!(0, a);
  assert_eq!(7, b);

  let Point {x, y} = p;
  assert_eq!(0, x);
  assert_eq!(7, y);

  match p {
    Point {x, y: 0} => println!("On the x axis at {}", x),
    Point {x: 0, y} => println!("On the y axis at {}", y),
    Point {x, y} => println!("On neither axis: ({}, {})", x, y),
  }
}

解构 enum

enum Message {
  Quit,
  Move {x: i32, y: i32},
  Write(String),
  ChangeColor(i32, i32, i32),
}

fn main() {
  let msg = Message::ChangeColor(0, 160, 255);

  match msg {
    Message::Quit => {
      println!("The Quit variant has no data to destructure.")
    }
    Message::Move {x, y} => {
      println!("Move in the x direction {} and in the y direction {}", x, y);
    }
    Message::Write(text) => println!("Text message: {}", text),
    Message::ChangeColor(r, g, b) => {
      println!("Change the color to red {}, green {}, and blue {}", r, g, b);
    }
  }
}

解构嵌套的 struct 和 enum

enum Color {
  Rgb(i32, i32, i32),
  Hsv(i32, i32, i32),
}

enum Message {
  Quit,
  Move {x: i32, y: i32},
  Write(String),
  ChangeColor(Color),
}

fn main() {
  let msg = Message::ChangeColor(Color::Hsv(0, 160, 255));

  match msg {
    Message::ChangeClolr(Color::Rgb(r, g, b)) => {
      println!("Change the color to red {}, green {}, and blur {}", r, g, b)
    }
    Message::ChangeColor(Color::Hsv(h, s, v)) => {
      println!("Change the color to hue {}, saturation {}, and value {}", h, s, v)
    }
    _ => (),
  }
}

解构 struct 和 tuple

struct Point {
  x: i32,
  y: i32,
}

fn main() {
  let ((feet, inches), Point {x, y}) = ((3, 10), Point {x: 3, y: -10});
}

在模式中忽略值

  • 有几种方式可以在模式中忽略整个值或部分值:
    • _
    • _ 配合其它模式
    • 使用以 _ 开头的名称
    • .. (忽略值的剩余部分)

使用 _ 来忽略整个值

fn foo(_: i32, y: i32) {
  println!("This code only uses the y parameter: {}", y);
}

fn main() {
  foo(3, 4);
}

使用嵌套的 _ 来忽略值的一部分

fn main() {
  let mut setting_value = Some(5);
  let new_setting_value = Some(10);

  match (setting_value, new_setting_value) {
    (Some(_), Some(_)) => {
      println!("Can't overwrite an existing customized value");
    }
    _ => {
      setting_value = new_setting_value;
    }
  }

  println!("setting is {:?}", setting_value);

  let numbers = (2, 4, 6, 8, 16, 32);

  match numbers {
    (first, _, third, _, fifth) => {
      println!("Some numbers: {}, {}, {}", first, third, fifth)
    }
  }
}

通过使用 _ 开头命名来忽略未使用的变量

fn main() {
  let _x = 5;
  let y = 10;  // 创建未使用 警告

  let s = Some(String::from("Hello"));

  if let Some(_s) = s { // if let Some(_) = s {
    println!("found a string");
  }

  println!("{:?}", s); // 报错 
}

使用 .. 来忽略值的剩余部分

struct Point {
  x: i32,
  y: i32,
  z: i32,
}

fn main() {
  let origin = Point {x: 0, y: 0, z: 0};
  match origin {
    Point {x, ..} => println!("x is {}", x),
  }

  let numbers = (2, 4, 8, 16, 32);
  match numbers {
    (first, .., last) => {
      println!("Some numbers: {}, {}", first, last);
    }
  }

  match numbers {
    (.., second, ..) => {  // 报错
      println!("Some numbers: {}", second)
    },
  }
}

使用 match 守卫来提供额外的条件

  • match 守卫就是 match arm 模式后额外的 if 条件,想要匹配该条件也必须满足
  • match 守卫适用于比单独的模式更复杂的场景

例子一:

fn main() {
  let num = Some(4);

  match num {
    Some(x) if x < 5 => println!("less than five: {}", x),
    Some(x) => println!("{}", x),
    None => (),
  }
}

例子二:

fn main() {
  let x = Some(5);
  let y = 10;

  match x {
    Some(50) => println!("Got 50"),
    Some(n) if n == y => println!("Matched, n = {:?}", n),
    _ => println!("Default case, x = {:?}", x),
  }

  println!("at the end: x = {:?}, y = {:?}", x, y);
}

例子三:

fn main() {
  let x = 4;
  let y = false;

  match x {
    4 | 5 | 6 if y => println!("yes"),
    _ => println!("no"),
  }
}

@绑定

  • @ 符号让我们可以创建一个变量,该变量可以在测试某个值是否与模式匹配的同时保存该值
enum Message {
  Hello {id: i32},
}

fn main() {
  let msg = Message::Hello {id: 5};

  match msg {
    Message::Hello {
      id: id_variable @ 3..=7,
    } => {
      println!("Found an id in range: {}", id_variable)
    }
    Message::Hello {id: 10..=12} => {
      println!("Found an id in another range")
    }
    Message::Hello {id} => {
      println!("Found some other id: {}", id)
    }
  }
}

总结

模式匹配在 Rust 中是一个灵活而强大的特性,为程序的控制流提供了极大的灵活性。通过使用 match、if let、while let 等语法,程序员可以在匹配结构中定义和解构不同的数据类型,简化代码逻辑。深入理解模式匹配的用法,将帮助开发者编写更具表达力的代码,为 Rust 编程带来新的思路与技巧。

参考

点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论