深入理解Rust的模式匹配
文章目录
- 基础用法
- 匹配各种类型
- 模式匹配赋值
- 提取绑定值
- 解构Option
- 高级用法
- 添加匹配守卫
- 范围匹配
- 切片模式
- 变量绑定
- 使用..进行模糊匹配
- 使用_进行值忽略
- 固定某个字段的匹配
- 多分支匹配
- 其它匹配方式
- if let匹配方式
- 使用matches!宏进行匹配
在Rust编程语言中,模式匹配是一种非常强大的功能,它允许开发者以灵活和表达性强的方式处理值。这是通过使用match语句和模式来实现的,它类似于其他语言中的switch语句,但提供了更多的灵活性和安全性。
基础用法
在Rust中match语句允许你将一个值与一系列模式进行比较,并根据匹配到的模式执行相应的代码块。
Rust的模式匹配支持多种不同的模式类型,包括:
1.字面值: 匹配具体的数值或者布尔值等。
2.绑定: 通过模式将值绑定到变量。
3.元组和结构体: 可以对元组或结构体的具体结构进行模式匹配。
4.枚举: 匹配枚举的不同变体。
5.引用: 匹配引用,包括通过解引用进行匹配。
6.范围: 匹配一个范围内的值,例如 1…=5 表示从 1 到 5 的所有值。
匹配各种类型
Rust中match语法的调用模版如下:
//语法结构
match target {
模式1 => 表达式1,
模式2 => {
语句1;
语句2;
表达式2
},
_ => 表达式3
}
匹配字面值
//匹配字面值
let x = 3;
match x {
1 => println!("one"),
2 => println!("two"),
3 => println!("three"),
//_用与匹配其它的参数 类似于C++的default
_ => println!("anything"),
}
匹配枚举值
//匹配枚举类型
enum Direction {
East,
West,
North,
South,
}
fn main() {
let dire = Direction::South;
match dire {
Direction::East => println!("East"),
//匹配North 或 South
Direction::North | Direction::South => {
println!("South or North");
},
//匹配剩余的其它类型
//除了_通配符,用一个变量来承载其他情况也是可以的
//other => println!("other direction: {:?}", other),
_ => println!("West"),
//_ =>() 空操作
};
}
匹配结构体
struct Point {
x: i32,
y: i32,
}
let point = Point { x: 0, y: 7 };
match point {
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 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::ChangeColor(Color::Rgb(r, g, b)) => {
}
Message::ChangeColor(Color::Hsv(h, s, v)) => {
}
_ => ()
}
}
模式匹配赋值
match本身也是一个表达式,除了可以用来处理业务逻辑之外还可以用来赋值。
enum IpAddr {
Ipv4,
Ipv6
}
fn main() {
let ip1 = IpAddr::Ipv6;
//模式匹配的结果赋值给ip_str
let ip_str = match ip1 {
IpAddr::Ipv4 => "127.0.0.1",
_ => "::1",
};
println!("{}", ip_str);
}
提取绑定值
在模式匹配的时候提取枚举中的绑定值。
//提取枚举值中绑定的数据
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 => {
}
Message::Move { x, y } => {
}
Message::Write(text) => println!("Text message: {}", text),
Message::ChangeColor(r, g, b) => {
}
}
}
解构Option
enum Option<T> {
None,
Some(T),
}
fn plus_one(x: Option<i32>) -> Option<i32> {
match x {
None => None,
Some(i) => Some(i + 1),
}
}
let five = Some(5);
let six = plus_one(five);
let none = plus_one(None);
高级用法
添加匹配守卫
match语句的模式可以包含守卫(guard),增加则外的条件判断,用于在模式匹配后进一步确定是否执行对应的代码块。
let num = Some(4);
match num {
//Some(x) 且x<5执行该语句 x<5就是匹配守卫 进行额外的条件判断
Some(x) if x < 5 => println!("less than five"),
Some(x) => println!("greater than or equal to five"),
None => (),
}
范围匹配
不用一个一个写对应的匹配值,直接匹配一定范围内的值。通过序列 …= 匹配值的范围
//匹配1--5
let x = 5;
match x {
1..=5 => println!("one through five"),
_ => println!("something else"),
}
//匹配a--j k--z
let x = 'c';
match x {
'a'..='j' => println!("early ASCII letter"),
'k'..='z' => println!("late ASCII letter"),
_ => println!("something else"),
}
切片模式
Rust的模式匹配还可以应用于数组和切片,这使得处理数据序列时更加灵活
let arr = [1, 2, 3];
match arr {
//匹配以1开头的数组
[1, _, _] => println!("Starts with one"),
//匹配以2为中间值的数组
[_, 2, _] => println!("Contains two in the middle"),
//匹配以3结尾的数组
[_, _, 3] => println!("Ends with three"),
//匹配其它值
_ => println!("Does not match any pattern"),
}
变量绑定
Rust的模式匹配还支持使用@进行绑定,这允许在进行模式匹配的同时,将匹配的值绑定到变量上.
//当你既想要限定分支范围,又想要使用分支的变量时,就可以用 @ 来绑定到一个新的变量上
enum Message {
Hello { id: i32 },
}
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)
},
}
使用…进行模糊匹配
//用 .. 忽略剩余值
struct Point {
x: i32,
y: i32,
z: i32,
}
let origin = Point { x: 0, y: 0, z: 0 };
match origin {
//不关心后续的值 只匹配第一个值
Point { x, .. } => println!("x is {}", x),
}
使用_进行值忽略
//使用_忽略整个值 忽略第一个参数 只使用第二个参数
fn foo(_: i32, y: i32) {
println!("This code only uses the y parameter: {}", y);
}
fn main() {
foo(3, 4);
}
//使用嵌套的_忽略部分值
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;
}
}
//忽略特定位置的值,只操作未被忽略的值
let numbers = (2, 4, 8, 16, 32);
match numbers {
(first, _, third, _, fifth) => {
println!("Some numbers: {}, {}, {}", first, third, fifth)
},
}
//使用下划线开头表示未使用的变量
//只使用_和使用以下划线开头的名称有些微妙的不同: 比如_x仍会将值绑定到变量,而_则完全不会绑定。
fn main() {
let _x = 5;
let y = 10;
}
固定某个字段的匹配
//固定某个字段的匹配模式
fn main() {
let p = Point { x: 0, y: 7 };
match p {
//y=0 的匹配
Point { x, y: 0 } => println!("On the x axis at {}", x),
//x=0 的匹配
Point { x: 0, y } => println!("On the y axis at {}", y),
Point { x, y } => println!("On neither axis: ({}, {})", x, y),
}
}
多分支匹配
增加了逻辑或操作,一个语句里面匹配多个条件
//多分支匹配
let x = 1;
match x {
1 | 2 => println!("one or two"),
3 => println!("three"),
_ => println!("anything"),
}
其它匹配方式
if let匹配方式
当你只要匹配一个条件,且忽略其他条件时就用if let ,否则都用match
let v = Some(3u8);
match v {
Some(3) => println!("three"),
_ => (),
}
//等价于
if let Some(3) = v {
println!("three");
}
使用matches!宏进行匹配
enum MyEnum {
Foo,
Bar
}
fn main() {
let v = vec![MyEnum::Foo,MyEnum::Bar,MyEnum::Foo];
//过滤Foo
v.iter().filter(|x| matches!(x, MyEnum::Foo));
//其它匹配方式
let foo = 'f';
assert!(matches!(foo, 'A'..='Z' | 'a'..='z'));
let bar = Some(4);
assert!(matches!(bar, Some(x) if x > 2));
}