👈 4 流程控制
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})");
}
全模式列表
参考:全模式列表。
👉 6 方法