Rust有许多很好的特性,模式匹配就是其中之一。Rust的模式匹配使代码具有表现力、可读性和清晰性。
Rust中的模式分为两种类型:条件匹配模式(refutable)和完全匹配模式(irrefutable)。使用哪一个取决于上下文。
1// Irrefutable patterns
2let x = 2;
3let (x, y) = (2, 3);
4
5// WILL NOT COMPILE
6// let does not allow refutable patterns
7let Ok(x) = someString.parse::<i32>()
8// trying to parse a string will return a Result, and can not guarantee that a result and not an Err is returned
1if let Ok(x) = someString.parse::<i32>() {
2 // ... do something if someString can be parsed as a 32 bit integer ...
3}
4
5// if let can have a refutable pattern, so we can also use a value for x:
6if let Ok(64) = someString.parse::<i32>() {
7 // ... do something if someString can be parsed as a 32 bit integer ...
8}
许多模式匹配用于解构数据类型,它们也可以混合在一起进行模式匹配。
1// myTuple is of type (i32, i32, &str)
2let my_tuple = (1, 2, "hellothere");
3let (x, y, my_str) = my_tuple;
在最后一行中,我们看到my_tuple被解构为3个新变量:x、y和my_str。这可以用于所有类型的元组,只要析构类型匹配。
1 // ignore my_str
2 let (x, y, _) = my_tuple;
3
4 // ignore everything after x
5 let (x, ..) = my_tuple;
6
7
8 // bigger tuple
9 let bigger_tuple = (1, 2, 3, 4, 5);
10
11 // get first and last
12 let (first, .., last) = bigger_tuple;
13
14 // ambiguous! NOT ALLOWED
15 // How would the compiler even know which element you wanted
16 let (.., middle, ..) = bigger_tuple;
1 // define a simple struct
2 struct Point {
3 x: f32,
4 y: f32,
5 z: f32
6 }
7
8 // create a variable to use
9 let myPoint = Point {
10 x: 1.0,
11 y: 0.5,
12 z: -1.0
13 };
14
15 // destructure it!
16 let Point { x, y, z} = my_point;
17
18 // Maybe we just want x and y?
19 let Point { x, y, .. } = my_point;
20
21 // or maybe just z
22 let Point { z, .. } = my_point;
在解构struct时应该注意的一件事是,名称必须与struct中找到的名称匹配,并且..必须放在最后,表示匹配其余部分并忽略结果。
1 // define a simple enum
2 enum Color {
3 Red,
4 Blue,
5 Green
6 }
7
8 // match if our color is green
9 if let Color::Green = my_color {
10 // .. do something is color is green ..
11 }
1 // More advanced enum
2 enum HttpRequest {
3 Get,
4 Post(String)
5 }
6
7 // match the post request
8 if let HttpRequest::Post(data) = my_request {
9 // .. do something with the post request data ...
10 }
11
12 // can also ignore data
13 if let HttpRequest::Post(_) = my_request {
14 // .. do something when post request ...
15 }
1 // Define some nested structure
2 enum Color {
3 Red,
4 Blue,
5 Green
6 }
7
8 // imagine old OpenGL from the early 2000s where colors of points were interpolated across the shape
9 struct Point {
10 x: f32,
11 y: f32,
12 z: f32,
13 color: Color
14 }
15
16 struct Triangle(Point, Point, Point);
17
18
19 // A destructuring based upon the data we want
20 // gvet only x for the first point when the first points color is blue
21 if let Triangle(
22 Point {
23 x,
24 color: Color::Blue, ..
25 },
26 ..,
27 ) = my_triangle {
28 // .. do something with the data we wanted for some reason ..
29 }
1 // matches 1, 2 or 3
2 1 | 2 | 3
3
4 // Matches one of the strings
5 "first" | "second"
1 // matches 1 to 10 (inclusive)
2 1..=10
3
4 // matches 1 to 10 (non-inclusive)
5 1..10
1// test data
2struct Vector2d {
3 x: f32,
4 y: f32
5}
6
7// destructured Vector2d
8fn length(Vector2d { x, y }: Vector2d) -> f32 {
9 (x.powi(2) + y.powi(2)).sqrt()
10}
11
12fn x_val(Vector2d { x, .. }: Vector2d) -> f32 {
13 x
14}