[ Rust笔记 七] 基础-模式解构(Pattern Destructure)

简介

1
2
let tuple = (1_i32, false, 3f32);
let (head, center, tail) = tuple;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
struct T1 (i32, char);
struct T2 {
item1: T1,
item2: bool,
}

fn main()
{
let x = T2 {
item1: T1(0, 'A'),
item2: false,
};
let T2 {
item1: T1(value1, value2),
item2: value3,
} = x;
println!("{} {} {}", value1, value2, value3);
}

match

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
enum Direction {
East, West, South, North
}
fn print(x: Direction)
{
match x {
Direction::East => {
println!("East");
}
Direction::West => {
println!("West");
}
Direction::South => {
println!("South");
}
Direction::North => {
println!("North");
}
}
}
fn main() {
let x = Direction::East;
print(x);
}

exhaustive

可以用一个下划线来表达“除了列出来的那些之外的其他情况”​,不然会报编译错误:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
    match x {
Direction::East => {
println!("East");
}
Direction::West => {
println!("West");
}
Direction::South => {
println!("South");
}
_ => {
println! ("Other");
}
}
1
2
3
4
5
6
#[non_exhaustive]
pub enum Error {
NotFound,
PermissionDenied,
ConnectionRefused,
}

“non_exhaustive”的attribute来标记一个enum或者struct,这样在另外一个项目中使用这个类型的时候,无论如何都没办法在match表达式中通过列举所有的成员实现完整匹配,必须使用下划线才能完成编译。

下划线

1
2
3
4
5
6
7
8
9
10
struct P(f32, f32, f32);
fn calc(arg: P) -> f32 {
// 匹配 tuple struct,但是忽略第二个成员的值
let P(x, _, y) = arg;
x * x + y * y
}
fn main() {
let t = P(1.0, 2.0, 3.0);
println! ("{}", calc(t));
}

等价写法

1
2
3
4
5
6
7
8
9
struct P(f32, f32, f32);
// 参数类型是 P,参数本身是一个模式,解构之后,变量x、y分别绑定了第一个和第三个成员
fn calc(P(x, _, y): P) -> f32 {
x * x + y * y
}
fn main() {
let t = P(1.0, 2.0, 3.0);
println! ("{}", calc(t));
}

下划线表示省略一个元素,两个点可以表示省略多个元素。

如果我们希望只匹配tuple中的第一个元素,其他的省略,那么用一个下划线是不行的,因为这样写,左边的tuple和右边的tuple不匹配。修改方案有两种。一种是

1
let (a, _, _) = x; // 用下划线,那么个数要匹配
1
2
let (a, ..) = x;   // 用两个点,表示其他的全部省略
let (a, .., b) = x; // 用两个点,表示只省略所有元素也是可以的

match也是表达式

match除了匹配“结构”​,还可以匹配“值”:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
enum Direction {
East, West, South, North
}
fn direction_to_int(x: Direction) -> i32
{
match x {
Direction::East => 10,
Direction::West => 20,
Direction::South => 30,
Direction::North => 40,
}
}
fn main() {
let x = Direction::East;
let s = direction_to_int(x);
println! ("{}", s);
}

我们可以使用或运算符|来匹配多个条件,比如:

1
2
3
4
5
6
7
8
9
10
11
fn category(x: i32) {
match x {
-1 | 1 => println! ("true"),
0 => println! ("false"),
_ => println! ("error"),
}
}
fn main() {
let x = 1;
category(x);
}

使用..=表示一个闭区间范围:

1
2
3
4
5
6
let x = 'X';
match x {
'a' ..= 'z' => println! ("lowercase"),
'A' ..= 'Z' => println! ("uppercase"),
_ => println! ("something else"),
}

Guards

1
2
3
4
5
6
7
8
9
10
enum OptionalInt {
Value(i32),
Missing,
}
let x = OptionalInt::Value(5);
match x {
OptionalInt::Value(i) if i > 5 => println! ("Got an int bigger than five! "),
OptionalInt::Value(..) => println! ("Got an int! "),
OptionalInt::Missing => println! ("No such luck."),
}

编译器没能完全覆盖住:

1
2
3
4
5
6
7
fn main() {//报错
let x = 10;
match x {
i if i > 5 => println! ("bigger than five"),
i if i <= 5 => println! ("small or equal to five"),
}
}

必须加上

1
_ => unreachable! (),

变量绑定

如果x在[1,5]范围内,则将1绑定到变量e

1
2
3
4
5
let x = 1;
match x {
e @ 1 ..= 5 => println! ("got a range element {}", e),
_ => println! ("anything"),
}

嵌套层次比较深的绑定

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#! [feature(exclusive_range_pattern)]
fn deep_match(v: Option<Option<i32>>) -> Option<i32> {
match v {
// r 绑定到的是第一层 Option 内部,r 的类型是 Option<i32>
// 与这种写法含义不一样:Some(Some(r)) if (1..10).contains(r)
Some(r @ Some(1..10)) => r,
_ => None,
}
}
fn main() {
let x = Some(Some(5));
println! ("{:? }", deep_match(x));
let y = Some(Some(100));
println! ("{:? }", deep_match(y));
}

‘|’表示所有都绑定

1
2
3
4
5
let x = 5;
match x {
e @ 1 .. 5 | e @ 8 .. 10 => println! ("got a range element {}", e),
_ => println! ("anything"),
}

ref和mut

有些晦涩难懂。。。啊啊啊啊。。。

函数和闭包参数做模式解构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
struct T {
item1: char,
item2: bool,
}
fn test( T{item1: arg1, item2: arg2} : T) {
println! ("{} {}", arg1, arg2);
}
fn main()
{
let x = T {
item1: 'A',
item2: false,
};
test(x);
}