match 和 if let
match 匹配
match 的通用形式:
match tar {
模式 1 => 表达式 1, // 单条表达式
模式 2 => { // 表达式块
语句 1;
语句 2;
表达式 2
},
_ => 表达式 3 // 用 _ 指代默认情况
}enum Direction {
East,
West,
North,
South,
}
fn main() {
let dir = Direction::South;
match dir {
Direction::East => println!("East"),
Direction::North | Direction::South => { // 匹配多个模式
println!("South / North");
},
_ => println!("West"),
};
}用 match 匹配枚举类型时:
- 所有分支需要完全覆盖枚举变量的所有成员类型。
- 用通配符
_表示未列出的其他模式。 - 在同一分支中可以用
|匹配多个模式。 - 每个分支必须返回一个表达式结果,且类型必须相同。
match 本身也是表达式,可用于赋值语句:
enum IpAddr {
Ipv4,
Ipv6
}
fn main() {
let ip = IpAddr::Ipv6;
let my_ip = match ip {
IpAddr::Ipv4 => "127.0.0.1",
IpAddr::Ipv6 => "::1",
};
println!("{my_ip}");
}也可用于函数返回值:
enum Coin {
Penny,
Nickel,
Dime,
Quarter,
}
fn value_in_cents(coin: Coin) -> u8 {
match coin {
Coin::Penny => {
println!("Lucky penny!");
1
},
Coin::Nickel => 5,
Coin::Dime => 10,
Coin::Quarter => 25,
}
}对于枚举 Coin,25 美分硬币上有各种州的图案,可将枚举 UsState 绑定到 Coin::Quarter 成员,称为模式绑定:
enum UsState {
Alabama,
Alaska,
// ...
}
enum Coin {
Penny,
Nickel,
Dime,
Quarter(UsState), // quarter 特有不同的州图案
}
fn value_in_cents(coin: Coin) -> u8 {
match coin {
Coin::Penny => {
println!("Lucky penny!");
1
},
Coin::Nickel => 5,
Coin::Dime => 10,
Coin::Quarter(state) => { // 用 state 匹配 UsState 实例
println!("State quarter from {:?}!", state);
25
},
}
}更复杂的例子:
enum Action {
Note(String),
MoveTo(i32, i32),
SetColor(u16, u16, u16),
}
fn main() {
let actions = [
Action::Note("Match!".to_string()),
Action::MoveTo(1, 2),
Action::SetColor(255, 255, 0),
];
for action in actions {
match action {
Action::Note(s) => {
println!("{s}");
}
Action::MoveTo(x, y) => {
println!("point moved to ({x}, {y})");
}
Action::SetColor(r, g, _) => {
println!("set color to '(r:{r}, g:{g}, b:0)', 'b' has been ignored");
}
}
}
}有些模式不重要,但又必须覆盖,可以使用通配模式或 _ 占位符:
// 通配模式: 匹配任何值并使用
let difficulty = 3;
match difficulty {
1 => println!("Easy~"),
2 => println!("Hard!"),
other => println!("{other} is not valid"),
};
// _ 占位符: 匹配任何值并丢弃
let difficulty = 3;
match difficulty {
1 => println!("Easy~"),
2 => println!("Hard!"),
_ => println!("not valid"),
};if let 匹配
只想匹配一种模式时,使用 match 将比较复杂:
let v = Some(3u8);
match v {
Some(3) => println!("v = 3"),
_ => {}
};而使用 if let 则简洁一些:
let v = Some(3u8);
if let Some(3) = v {
println!("v = 3");
}if let 是 match 在只希望匹配一种模式下的语法糖:
// match
let config_max = Some(3u8);
match config_max {
Some(max) => println!("The maximum is configured to be {max}"),
_ => {}
}
// 等价的 if let
let config_max = Some(3u8);
if let Some(max) = config_max {
println!("The maximum is configured to be {max}");
}if let 后可以跟 else:
for coin in coins.iter() {
if let Coin::Quarter(state) = coin {
println!("State quarter from {:?}!", state);
} else {
println!("Not a quarter");
}
}在简单的例子中,用 if 语句更合适:
let v = Some(3u8);
if v == Some(3) {
println!("v = 3");
}不过解构更复杂的情况才是 if let 的用武之地:
enum Result {
Success(i32),
Failure(String),
}
fn main() {
let res = Result::Success(123);
if let Result::Success(val) = res {
println!("Operation succeeded with value: {val}");
} else {
println!("Operation failed.");
}
}match 和 if let 的选择:如果只想要匹配一个条件而忽略其余条件,使用 if let,否则使用 match。
matches! 宏
matches! 宏将一个表达式与模式进行匹配,返回一个 bool 表示匹配结果。
enum MyEnum {
Foo,
Bar,
}
fn main() {
let v = vec![MyEnum::Foo, MyEnum::Bar, MyEnum::Foo];
}现需要对 v 进行过滤,只保留类型为 MyEnum::Foo 的元素:
// not ok
v.iter().filter(|x| x == MyEnum::Foo);这是不正确的,应该使用 matches! 宏:
// ok
v.iter().filter(|x| matches!(x, MyEnum::Foo));更多示例:
let foo = 'f';
assert!(matches!(foo, 'A'..='Z' | 'a'..='z')); // success
let bar = Some(4);
assert!(matches!(bar, Some(x) if x > 2)); // success解构 Option
Option 的定义:
enum Option<T> {
Some(T),
None,
}一个 Option 实例要么有值 Some(T),要么为空 None。
使用 Option<T> 的意义是从 Some 中取出 T 值,或者处理值为空的情况。
fn main() {
let five = Some(5);
let six = plus_one(five); // Some(6)
let none = plus_one(None); // None
}
fn plus_one(x: Option<i32>) -> Option<i32> {
match x {
Some(i) => Some(i + 1),
None => None,
}
}plus_one 接收一个 Option<i32>,并返回一个 Option<i32>:
- 如果传入一个
Some(i32),则通过match将其中的值绑定到i,再返回Some包裹的i+1。 - 如果传入一个
None,则直接返回一个None。
模式适用场景
match分支if let分支while let条件循环for循环let语句- 函数参数
while let 条件循环
类似于 if let,不过只要模式一直匹配就保持循环。
let mut stack = Vec::new();
stack.push(1);
stack.push(2);
stack.push(3);
while let Some(top) = stack.pop() { // 弹完即止
println!("{top}");
}函数参数
参数即为模式,还可以在参数中匹配元组:
fn print_point(&(x, y): &(i32, i32)) {
println!("({x}, {y})");
}全模式列表
参考:全模式列表。