Rust 模式匹配

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

let 語句是完全匹配模式,不允許條件匹配。而 if let 語句是條件匹配模式:

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。這可以用於所有類型的元組,只要析構類型匹配。

你也可以用..(可能是多個) 或_ (single),它們通常用於跳過元素:

 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;

Structs

 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  }

組合

你也可以將以上所有的類型組合成你自己的模式!枚舉中的 struct,元組中的枚舉等等。這樣的例子不勝枚舉!

 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  }

其他模式

or-matcher

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

範圍還可以用作數組的索引,以獲取多個元素。

函數簽名中的模式匹配

可以在函數定義中使用模式!這真的很酷,對吧?你必須記住,這些模式必須是完全匹配模式,就像 let。

 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}

本文翻譯自:

https://dev.to/themkat/the-awesomeness-of-pattern-matching-in-rust-3lbn

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/KYXDYxT4Cl_5l9Xaq2XvJw