在 Rust 中没有 switch
语句,但是提供了匹配器 matcher
,相比其它语言中的 switch
要更强大。
基本概念
match
语句是 Rust 中的一种控制流语句,可以根据不同的模式匹配执行不同的代码,其基本语法如下:
match value {
pattern1 => {
// code1
}
pattern2 => {
// code2
}
_ => {
// not match
}
}
其中 value
是要匹配的变量,pattern
是匹配模式,=>
后面是要执行的代码块,如果 value
匹配了某个模式,就会执行对应的代码块;如果 value
没有匹配任何模式,就会执行默认的代码块,也就是 _ => {...}
模块。
简单示例
这是 Rust 中比较常用的语法,用来匹配类型中的结构,无论类型是简单还是复杂。模式常见于如下场景:参数析构、match 等。
fn main() {
let x = 1;
match x {
0 => println!("zero"), // Simple patterns
1 | 2 => println!("one or two"), // Multiple patterns
3 ..= 5 => println!("three to five"), // Ranges [3, 5]
v @ 6 ..= 10 => println!("got a range element {}", v), // Bindings
_ => println!("anything"),
}
}
如上的最简单的示例,支持匹配单个值、多个值、范围等,允许绑定到某个变量然后直接引用。
枚举
enum Operation {
Quit,
Move {x: i32, y: i32},
Message(String),
}
fn main() {
let msg = Operation::Move { x: 1, y: 2 };
match msg {
Operation::Quit => return,
Operation::Move { x, y }=> println!("POS=({}, {})", x, y),
Operation::Message(s)=> println!("MSG=({})", s),
_ => return,
}
}
可以定义一个枚举类型,然后根据枚举中的不同类型匹配,允许从中提取变量。
最常用的还是标准的 Option
类型,示例如下。
fn main() {
let y = Some(10);
match y {
Option::Some(i) if i > 5 => println!("got value {}", i), // Match guards
Option::Some(..) => println!("some value"), // Ignoring the value and type
Option::None => println!("none"),
}
}
引用
fn main() {
let z = 10;
match z {
ref r => {println!("A reference {}", r);} // Must surrounded by a body
}
let mut u = 10;
match u {
ref mut r => {println!("A mutable reference {}", r);} // Mutable
}
let r = &z;
match r {
&10 => println!("The value is ten"),
_ => println!("The value is not ten"),
}
}
允许匹配某个引用类型,甚至是具体的某个值。
高级用法
元组和结构体
fn main() {
struct Point {
x: i32,
y: i32,
}
let p = Point {x: 10, y: 20};
match p {
Point {y: yy, .. } => {println!("y is {}", yy);}
}
let point = (1, 2);
match point {
(0, 0) => println!("The point is at the origin"),
(_, 0) => println!("The point is on the x-axis"),
(0, _) => println!("The point is on the y-axis"),
(x, y) => println!("The point is at ({}, {})", x, y),
}
}
上述的结构体示例中仅获取其中一个变量,还可以使用 Point { x: Some(ref name), y: None } => ...
这种方式,只是其中的 x
为 Some
类型,然后从其中获取引用,并命名为 name 变量。
守卫
fn main() {
let x = 5;
match x {
n if n < 0 => println!("The value is negative, {}", n),
n if n > 10 => println!("The value is greater than 10, {}", n),
_ => println!("The value is between 0 and 10"),
}
}
除了匹配某个值还可以设置某个条件,当满足具体条件时才执行对应的分支。
绑定变量
fn main() {
let x = Some(5);
match x {
Some(n @ 1..=10) => println!("The value is between 1 and 10: {}", n),
Some(n @ 11..=20) => println!("The value is between 11 and 20: {}", n),
Some(_) => println!("The value is not between 1 and 20"),
None => (),
}
}
也就是通过 @
绑定变量,后面代码可以直接使用;或者通过 _
忽略对应的值。
简化匹配
fn main() {
let x = Some(5);
if let Some(n) = x {
println!("The value is {}", n);
} else {
println!("The value is None");
}
}
使用的时候可能只需要查看是否满足其中一种条件,那么就可以简单通过 if let
这种语法糖的方式使用。
简化循环
fn main() {
let v = vec![1, 2, 3];
for n in &v {
println!("{}", n);
}
let mut v = vec![1, 2, 3];
while let Some(n) = v.pop() {
println!("{}", n);
}
}
可以通过 while let
简化循环的处理逻辑。
简化使用
除了上述的 match
方式,还可以使用 if let
的方式,区别是,后者不会检查是否关联了所有分支。
enum Direction {
Up,
Down,
Left,
Right,
}
let dir = Direction::Down;
if let Direction::Left = dir {
println!("Left");
} else if let Direction::Right = dir {
println!("Right");
} else {
println!("Dummy");
}