前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Rust模式探索:写出更优雅的Rust代码

Rust模式探索:写出更优雅的Rust代码

作者头像
草帽lufei
发布2024-05-08 15:24:17
660
发布2024-05-08 15:24:17
举报
文章被收录于专栏:程序语言交流程序语言交流
模式定义

在Rust中,模式匹配是一种强大的编程工具,它允许你根据数据的结构来选择不同的执行路径。模式可以用在 match 表达式、if let 表达式、while let 表达式、函数参数、let 语句等地方

一个示例

来看个上一篇文章 Rust 枚举 简单入门 中例子

代码语言:javascript
复制
enum Color {
    Red,
    Orange,
    Yellow
}

let c1 = Color::Red;

match c1 {
    Color::Red => println!("Red"),
    Color::Orange => println!("Orange"),
    Color::Yellow => println!("Yellow")
}

match 会执行模式匹配,在此示例中,模式就是出现在 => 符号前面的部分,模式匹配可以和枚举协同工作,甚至可以测试它们包含的数据

模式类型

上面的例子是匹配枚举值的模式。模式的类型不止于此,Rust 模式还有它们自己的小型语言,如下表

模式类型

例子

注意事项

字面量

100 "name"

匹配一个确切的值;也允许匹配常量名称

范围

0 ..= 100 'a' ..= 'k' 256..

匹配范围内的任何值,包括可能给定的结束值

通配符

_

匹配任何值并忽略它

变量

name mut count

类似于 _,但会把值移动或复制到新的局部变量中

引用变量

ref field ref mut field

借用对匹配值的引用,而不是移动或复制它

与子模式绑定

val @ 0 ..= 99 ref circle @ Shape::Circle { .. }

使用 @ 左边的变量名,匹配其右边的模式

枚举型模式

Some(value) None Pet::Orca

元组型模式

(key, value) (r, g, b)

数组型模式

[a, b, c, d, e, f, g] [heading, carom, correction]

切片型模式

[first, second] [first, _, third] [first, .., nth] [ ]

结构体型模式

Color(r, g, b) Point { x, y } Card { suit: Clubs, rank: n } Account { id, name, .. }

引用

&value &(k, v)

仅匹配引用值

或多个模式

'a' 竖线 'A' Some("left" 竖线 "right")

守卫表达式

x if x * x <= r2

只用在 match 表达式中(不能用在 let 语句等处)

注意! 由于当前页面的 Markdown 格式转换问题,竖线 | 会导致排版异常,因此上面表格使用中文 竖线 代替 |

字面量、变量、通配符

字面量可以是整数、浮点数、字符、字符串、布尔值等。下面是整数字面量的一个例子

代码语言:javascript
复制
let x = 5;

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

用单个下划线 _ 作为模式,这就是通配符模式,这里的通配符模式能匹配任意值,但不会将其存储到任何地方

即使你非常确定其他情况不会发生,也必须至少添加一个后备分支,也许是 panic 的分支

代码语言:javascript
复制
let s = "hello";

match s {
    "hello" => println!("found hello"),
    other => println!("no match"),
}

这里面的 other 是一个变量名,它可以匹配任何值,匹配的值会移动或复制到一个新的局部变量中,这些模式类似 switch 语句中的 default 分支,用于匹配与任何其他模式都无法匹配的值

元组型和结构体型

元组模式是一种模式,用于匹配元组的结构。元组模式由一对圆括号和一组模式组成,模式之间用逗号分隔

代码语言:javascript
复制
let x = (1, 2, 3);

match x {
    (1, 2, 3) => println!("one, two, three"),
    (a, b, c) => println!("({}, {}, {})", a, b, c),
}

结构体模式用于匹配结构体的结构。结构体模式由结构体的名称和一组模式组成,模式之间用逗号分隔

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

let p = Point { x: 0, y: 7 };

match p {
    Point { x, y: 0 } => println!("x is {}, y is on the x axis", x),
    Point { x: 0, y } => println!("x is on the y axis, y is {}", y),
    Point { x, y } => println!("x is {}, y is {}", x, y),
}

当想要匹配一个大型结构体的一部分字段,而不是全部字段时,可以使用 .. 来表示剩余的字段。这被称为结构体模式的 .. 简写

代码语言:javascript
复制
struct Point {
    x: i32,
    y: i32,
    z: i32,
    // ... 其他字段
}

let p = Point { x: 0, y: 7, z: 0 };

match p {
    Point { x, .. } => println!("x is {}", x),
}

match 表达式只关心 px 字段,而不关心 yz 字段。.. 表示剩余的字段,所以Point { x, .. }匹配任何 Point 结构体,只要它的 x 字段匹配

数组型和切片型

数组型模式匹配数组。数组型模式通常用于过滤一些特殊情况的值,并且在处理那些不同位置的值具有不同含义的数组时也非常有用

代码语言:javascript
复制
let arr = [1, 2, 3];

match arr {
    [1, 2, 3] => println!("found 1, 2, 3"),
    _ => println!("no match"),
}

注意! 数组模式只能用于固定大小的数组,不能用于动态大小的数组(也就是切片)。如果你想要匹配一个切片的结构,你应该使用切片模式

切片型模式与数组型相似,但与数组不同,切片具有可变长度,因此切片型模式不仅匹配值,还匹配长度。.. 在切片型模式中能匹配任意数量的元素

代码语言:javascript
复制
let arr = ["a"];

match &arr[..] {
    [] => println!("no body"),
    [a] => println!("a"),
    [a, b] => println!("a, b"),
    _ => println!("no match"),
}

引用型模式

引用型模式(Reference Patterns)允许你通过引用来匹配和解构数据,而不是通过值。这种模式在处理借用的数据时特别有用,因为它允许你在不获取所有权的情况下访问数据的部分或全部内容

基本用法

引用型模式通常与&符号一起使用,表示你正在匹配一个引用。当你想要在模式匹配中解构一个引用指向的值时,这非常有用,下面是个简单的例子

代码语言:javascript
复制
let reference = &10;

match reference {
    &val => println!("val: {:?}", val)
}

reference是一个指向10的引用。在match表达式中,模式&val用于解构reference,允许直接访问它指向的值10

解构数据

引用型模式在解构复杂数据结构时尤其有用,比如元组或结构体

代码语言:javascript
复制
let tuple = &(1, 2, 3);

match tuple {
    &(x, y, z) => println!("Matched: {}, {}, {}", x, y, z),
}
使用ref关键字

ref关键字用于创建一个引用指向模式匹配中的值,而不是通过值绑定

代码语言:javascript
复制
let value = 5;
let ref reference = value;

match reference {
    &val => println!("val: {:?}", val),
}
ref和mut结合使用

ref mut可以用来匹配可变引用,并允许修改通过引用访问的数据

代码语言:javascript
复制

let mut value = 5;

match value {
    ref mut r => {
        *r += 10;
        println!("value: {}", r);
    }
}
注意!
  • 使用ref mut时,必须确保被引用的数据本身是可变的
  • 修改通过ref mut创建的引用所指向的数据时,需要使用解引用操作符*
  • 在模式匹配中使用ref和ref mut可以让你更灵活地处理数据,特别是在需要引用而不是所有权的场景中

匹配守卫

匹配守卫(match guards)是一种与模式匹配结合使用的条件表达式,它提供了额外的条件来决定是否应该选择某个分支。这使得模式匹配更加灵活,允许在模式本身无法表达的复杂情况下进行精细的控制

匹配守卫紧跟在模式之后,使用if关键字引入,如下例子

代码语言:javascript
复制
let tuple = (5, 12);

match tuple {
    (5, y) if y > 10 => println!("第一个元素是5,且第二个元素大于10,y = {}", y),
    _ => println!("不匹配"),
}

在循环中使用匹配守卫

代码语言:javascript
复制
let numbers = vec![Some(10), Some(11), Some(20), Some(30)];

for option in numbers.iter() {
    match option {
        Some(x) if *x > 10 => println!("大于10的数字为:{}", x),
        _ => (),
    }
}

匹配多种可能性

模式匹配(Pattern Matching)是一种强大的控制流工具,它不仅可以匹配单一的值,还可以同时匹配多种可能性。这通过使用|运算符来实现,|在这里表示“或”(or),允许在同一个match分支中指定多个模式

代码语言:javascript
复制
let pair = (2, 3);
match pair {
    (x, y) if x == y => println!("数字一样"),
    (x, 0) | (0, x) => println!("x: {}", x),
    _ => println!("没有匹配")
}

使用@模式绑定

@模式绑定的基本语法是在模式中使用@后跟一个变量名,这样可以在模式匹配成功时,将匹配到的值绑定到这个变量

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

let move_message = Message::Move { x: 3, y: 104 };

match  move_message {
    Message::Move { x: x_pos @ 0..=100, y: y_pos @ 101..=200 } => {
        println!("移出({}, {})", x_pos, y_pos)
    },
    _ => println!("other")
}

模式能用在哪里

尽管模式在 match 表达式中作用最为突出,但它们也可以出现在其他一些地方,通常用于代替标识符。但无论出现在哪里,其含义都是一样的:Rust 不是要将值存储到单个变量中,而是使用模式匹配来拆分值

代码语言:javascript
复制
// 把结构体解包成3个局部变量……
let Track { album, track_number, title, .. } = song;

// ……解包某个作为函数参数传入的元组
fn distance_to((x, y): (f64, f64)) -> f64 { ... }

// ……迭代某个HashMap上的键和值
for (id, document) in &cache_map {
    println!("Document #{}: {}", id, document.title);
}

上述示例中的每一个都节省了两三行样板代码。同样的概念也存在于其他一些语言中:JavaScript 中叫作解构,而 Python 中叫作解包

看到这里,有没有越看越顺的感觉?😁

欢迎大家讨论交流,如果喜欢本文章或感觉文章有用,动动你那发财的小手点赞、收藏、关注再走呗

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-04-14,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 草帽Lufei 微信公众号,前往查看

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一个示例
  • 模式类型
    • 字面量、变量、通配符
      • 元组型和结构体型
        • 数组型和切片型
          • 引用型模式
            • 基本用法
            • 解构数据
            • 使用ref关键字
            • ref和mut结合使用
          • 匹配守卫
            • 匹配多种可能性
              • 使用@模式绑定
              • 模式能用在哪里
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档