模式匹配(pattern matching)
1. match
表达式
match
表达式是Rust中最常用的模式匹配工具,用于将一个值与多个模式进行比较,并执行相应的代码块。
fn main() {
let number = 7;
match number {
1 => println!("One!"),
2 | 3 | 5 | 7 | 11 => println!("This is a prime"),
13..=19 => println!("A teen number"),
_ => println!("Some other number"),
}
}
1.1 模式匹配基础
- 单值匹配:匹配具体的单个值,如
1
。 - 多值匹配:使用
|
匹配多个值,如2 | 3 | 5 | 7 | 11
。 - 范围匹配:使用
..=
匹配一个范围内的值,如13..=19
。 - 通配符模式:使用
_
匹配所有其他值。
2. 解构结构体、枚举和元组
模式匹配可以用于解构复杂的数据结构,如结构体、枚举和元组。
2.1 解构元组
fn main() {
let pair = (0, -2);
match pair {
(0, y) => println!("First is zero and y is {}", y),
(x, 0) => println!("x is {} and second is zero", x),
_ => println!("It is a pair of other values"),
}
}
2.2 解构枚举
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),
}
}
2.3 解构结构体
struct Point {
x: i32,
y: i32,
}
fn main() {
let p = Point { x: 0, y: 7 };
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),
}
}
3. if let
和 while let
if let
和 while let
提供了一种简洁的方式,只在匹配一个模式时执行代码。
3.1 if let
表达式
let some_value = Some(5);
if let Some(x) = some_value {
println!("Matched! x = {}", x);
}
3.2 while let
表达式
let mut stack = vec![1, 2, 3];
while let Some(top) = stack.pop() {
println!("{}", top);
}
4. 函数参数模式匹配
在函数参数中也可以使用模式匹配,以解构传入的参数。
struct Point {
x: i32,
y: i32,
}
fn print_coordinates(&Point { x, y }: &Point) {
println!("Current location: ({}, {})", x, y);
}
fn main() {
let point = Point { x: 3, y: 5 };
print_coordinates(&point);
}
5. 绑定和守卫
5.1 绑定
在模式中使用@
符号可以绑定部分模式到变量。
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)
}
}
}
5.2 守卫
模式守卫是附加在匹配条件上的额外if
条件。
let num = Some(4);
match num {
Some(x) if x < 5 => println!("Less than five: {}", x),
Some(x) => println!("{}", x),
None => (),
}
6. 使用 _
忽略值
在模式匹配中,可以使用 _
忽略某些值或模式。
fn main() {
let tuple = (1, 2, 3, 4, 5);
match tuple {
(first, _, third, _, fifth) => {
println!("Values are: {}, {}, {}", first, third, fifth);
}
}
}
7. 使用 ref
和 ref mut
在模式中使用ref
和ref mut
来获得值的引用而不是值本身。
fn main() {
let mut robot_name = Some(String::from("Bors"));
match robot_name {
Some(ref mut name) => *name = String::from("Bors-2.0"),
None => (),
}
println!("robot_name: {:?}", robot_name);
}
8. 复杂模式匹配示例
为了更好地理解Rust中的模式匹配,这里展示一些复杂的示例,包括嵌套模式和组合模式。
8.1 嵌套模式
嵌套模式允许你匹配更深层次的数据结构。这在处理复杂的枚举类型时非常有用。
enum Color {
Red,
Blue,
Green,
}
enum Vehicle {
Car { color: Color, model: String },
Bike { color: Color, gears: u8 },
}
fn main() {
let my_vehicle = Vehicle::Car {
color: Color::Red,
model: String::from("Tesla Model S")
};
match my_vehicle {
Vehicle::Car { color: Color::Red, model } => {
println!("It's a red car, model: {}", model);
}
Vehicle::Car { color, model } => {
println!("It's a {:?} car, model: {}", color, model);
}
Vehicle::Bike { color, gears } => {
println!("It's a {:?} bike with {} gears", color, gears);
}
}
}
在这个示例中,我们定义了两个枚举Color
和Vehicle
,并在match
表达式中使用嵌套模式来匹配车辆的颜色和类型。
8.2 组合模式
组合模式允许你在一个匹配分支中使用多个模式。
fn main() {
let x = 5;
match x {
1 | 2 |3..=7 => println!("One or two or three to seven"),
_ => println!("Anything else"),
}
}
在这个示例中,我们在同一个匹配分支中使用了多个模式(1 | 2
)和范围模式(3..=7
)。
9. 更多模式匹配特性
9.1 使用 @
绑定值
使用@
符号,你可以在模式中绑定值,同时解构它们。
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 } => {
println!("Found some other id: {}", id)
}
}
}
在这个示例中,id_variable @ 3..=7
模式不仅匹配范围3..=7
内的值,还将匹配的值绑定到id_variable
变量。
9.2 使用 _
忽略未使用的值
使用_
符号可以忽略匹配时不需要的值。
fn main() {
let (a, _, c) = (1, 2, 3);
println!("a: {}, c: {}", a, c);
}
在这个示例中,我们忽略了元组中的第二个值2
。
10. 高级模式匹配
10.1 高级守卫模式
模式守卫可以使用逻辑运算符来实现更复杂的条件。
fn main() {
let num = Some(4);
match num {
Some(x) if x % 2 == 0 && x > 2 => println!("Matched even number greater than 2: {}", x),
Some(x) => println!("Other number: {}", x),
None => (),
}
}
在这个示例中,模式守卫if x % 2 == 0 && x > 2
同时检查两个条件。
10.2 使用 ref
和 ref mut
获得引用
在模式中使用ref
和ref mut
可以获取值的引用而不是值本身。
fn main() {
let name = Some(String::from("Alice"));
match name {
Some(ref n) => println!("Found a name: {}", n),
None => println!("No name found"),
}
}
在这个示例中,Some(ref n)
模式获取String
的引用而不是所有权。