W3Cschool
恭喜您成為首批注冊(cè)用戶
獲得88經(jīng)驗(yàn)值獎(jiǎng)勵(lì)
ch18-01-all-the-places-for-patterns.md
commit 8a1aad812b90126974853f80d9217e07bd226650
模式出現(xiàn)在 Rust 的很多地方。你已經(jīng)在不經(jīng)意間使用了很多模式!本部分是一個(gè)所有有效模式位置的參考。
如第六章所討論的,一個(gè)模式常用的位置是 match
表達(dá)式的分支。在形式上 match
表達(dá)式由 match
關(guān)鍵字、用于匹配的值和一個(gè)或多個(gè)分支構(gòu)成,這些分支包含一個(gè)模式和在值匹配分支的模式時(shí)運(yùn)行的表達(dá)式:
match VALUE {
PATTERN => EXPRESSION,
PATTERN => EXPRESSION,
PATTERN => EXPRESSION,
}
match
表達(dá)式必須是 窮盡(exhaustive)的,意為 match
表達(dá)式所有可能的值都必須被考慮到。一個(gè)確保覆蓋每個(gè)可能值的方法是在最后一個(gè)分支使用捕獲所有的模式:比如,一個(gè)匹配任何值的名稱永遠(yuǎn)也不會(huì)失敗,因此可以覆蓋所有匹配剩下的情況。
有一個(gè)特定的模式 _
可以匹配所有情況,不過它從不綁定任何變量。這在例如希望忽略任何未指定值的情況很有用。本章之后的 “忽略模式中的值” 部分會(huì)詳細(xì)介紹 _
模式的更多細(xì)節(jié)。
第六章討論過了 if let
表達(dá)式,以及它是如何主要用于編寫等同于只關(guān)心一個(gè)情況的 match
語(yǔ)句簡(jiǎn)寫的。if let
可以對(duì)應(yīng)一個(gè)可選的帶有代碼的 else
在 if let
中的模式不匹配時(shí)運(yùn)行。
示例 18-1 展示了也可以組合并匹配 if let
、else if
和 else if let
表達(dá)式。這相比 match
表達(dá)式一次只能將一個(gè)值與模式比較提供了更多靈活性;一系列 if let
、else if
、else if let
分支并不要求其條件相互關(guān)聯(lián)。
示例 18-1 中的代碼展示了一系列針對(duì)不同條件的檢查來(lái)決定背景顏色應(yīng)該是什么。為了達(dá)到這個(gè)例子的目的,我們創(chuàng)建了硬編碼值的變量,在真實(shí)程序中則可能由詢問用戶獲得。
文件名: src/main.rs
fn main() {
let favorite_color: Option<&str> = None;
let is_tuesday = false;
let age: Result<u8, _> = "34".parse();
if let Some(color) = favorite_color {
println!("Using your favorite color, {}, as the background", color);
} else if is_tuesday {
println!("Tuesday is green day!");
} else if let Ok(age) = age {
if age > 30 {
println!("Using purple as the background color");
} else {
println!("Using orange as the background color");
}
} else {
println!("Using blue as the background color");
}
}
示例 18-1: 結(jié)合 if let
、else if
、else if let
以及 else
如果用戶指定了中意的顏色,將使用其作為背景顏色。如果今天是星期二,背景顏色將是綠色。如果用戶指定了他們的年齡字符串并能夠成功將其解析為數(shù)字的話,我們將根據(jù)這個(gè)數(shù)字使用紫色或者橙色。最后,如果沒有一個(gè)條件符合,背景顏色將是藍(lán)色:
這個(gè)條件結(jié)構(gòu)允許我們支持復(fù)雜的需求。使用這里硬編碼的值,例子會(huì)打印出 Using purple as the background color
。
注意 if let
也可以像 match
分支那樣引入覆蓋變量:if let Ok(age) = age
引入了一個(gè)新的覆蓋變量 age
,它包含 Ok
成員中的值。這意味著 if age > 30
條件需要位于這個(gè)代碼塊內(nèi)部;不能將兩個(gè)條件組合為 if let Ok(age) = age && age > 30
,因?yàn)槲覀兿Mc 30 進(jìn)行比較的被覆蓋的 age
直到大括號(hào)開始的新作用域才是有效的。
if let
表達(dá)式的缺點(diǎn)在于其窮盡性沒有為編譯器所檢查,而 match
表達(dá)式則檢查了。如果去掉最后的 else
塊而遺漏處理一些情況,編譯器也不會(huì)警告這類可能的邏輯錯(cuò)誤。
一個(gè)與 if let
結(jié)構(gòu)類似的是 while let
條件循環(huán),它允許只要模式匹配就一直進(jìn)行 while
循環(huán)。示例 18-2 展示了一個(gè)使用 while let
的例子,它使用 vector 作為棧并以先進(jìn)后出的方式打印出 vector 中的值:
let mut stack = Vec::new();
stack.push(1);
stack.push(2);
stack.push(3);
while let Some(top) = stack.pop() {
println!("{}", top);
}
列表 18-2: 使用 while let
循環(huán)只要 stack.pop()
返回 Some
就打印出其值
這個(gè)例子會(huì)打印出 3、2 接著是 1。pop
方法取出 vector 的最后一個(gè)元素并返回 Some(value)
。如果 vector 是空的,它返回 None
。while
循環(huán)只要 pop
返回 Some
就會(huì)一直運(yùn)行其塊中的代碼。一旦其返回 None
,while
循環(huán)停止。我們可以使用 while let
來(lái)彈出棧中的每一個(gè)元素。
如同第三章所講的,for
循環(huán)是 Rust 中最常見的循環(huán)結(jié)構(gòu),不過還沒有講到的是 for
可以獲取一個(gè)模式。在 for
循環(huán)中,模式是 for
關(guān)鍵字直接跟隨的值,正如 for x in y
中的 x
。
示例 18-3 中展示了如何使用 for
循環(huán)來(lái)解構(gòu),或拆開一個(gè)元組作為 for
循環(huán)的一部分:
let v = vec!['a', 'b', 'c'];
for (index, value) in v.iter().enumerate() {
println!("{} is at index {}", value, index);
}
列表 18-3: 在 for
循環(huán)中使用模式來(lái)解構(gòu)元組
示例 18-3 的代碼會(huì)打印出:
$ cargo run
Compiling patterns v0.1.0 (file:///projects/patterns)
Finished dev [unoptimized + debuginfo] target(s) in 0.52s
Running `target/debug/patterns`
a is at index 0
b is at index 1
c is at index 2
這里使用 enumerate
方法適配一個(gè)迭代器來(lái)產(chǎn)生一個(gè)值和其在迭代器中的索引,他們位于一個(gè)元組中。第一個(gè)產(chǎn)生的值是元組 (0, 'a')
。當(dāng)這個(gè)值匹配模式 (index, value)
,index
將會(huì)是 0 而 value
將會(huì)是 'a'
,并打印出第一行輸出。
在本章之前,我們只明確的討論過通過 match
和 if let
使用模式,不過事實(shí)上也在別的地方使用過模式,包括 let
語(yǔ)句。例如,考慮一下這個(gè)直白的 let
變量賦值:
let x = 5;
本書進(jìn)行了不下百次這樣的操作,不過你可能沒有發(fā)覺,這正是在使用模式!let
語(yǔ)句更為正式的樣子如下:
let PATTERN = EXPRESSION;
像 let x = 5;
這樣的語(yǔ)句中變量名位于 PATTERN
位置,變量名不過是形式特別樸素的模式。我們將表達(dá)式與模式比較,并為任何找到的名稱賦值。所以例如 let x = 5;
的情況,x
是一個(gè)代表 “將匹配到的值綁定到變量 x” 的模式。同時(shí)因?yàn)槊Q x
是整個(gè)模式,這個(gè)模式實(shí)際上等于 “將任何值綁定到變量 x
,不管值是什么”。
為了更清楚的理解 let
的模式匹配方面的內(nèi)容,考慮示例 18-4 中使用 let
和模式解構(gòu)一個(gè)元組:
let (x, y, z) = (1, 2, 3);
示例 18-4: 使用模式解構(gòu)元組并一次創(chuàng)建三個(gè)變量
這里將一個(gè)元組與模式匹配。Rust 會(huì)比較值 (1, 2, 3)
與模式 (x, y, z)
并發(fā)現(xiàn)此值匹配這個(gè)模式。在這個(gè)例子中,將會(huì)把 1
綁定到 x
,2
綁定到 y
并將 3
綁定到 z
。你可以將這個(gè)元組模式看作是將三個(gè)獨(dú)立的變量模式結(jié)合在一起。
如果模式中元素的數(shù)量不匹配元組中元素的數(shù)量,則整個(gè)類型不匹配,并會(huì)得到一個(gè)編譯時(shí)錯(cuò)誤。例如,示例 18-5 展示了嘗試用兩個(gè)變量解構(gòu)三個(gè)元素的元組,這是不行的:
let (x, y) = (1, 2, 3);
示例 18-5: 一個(gè)錯(cuò)誤的模式結(jié)構(gòu),其中變量的數(shù)量不符合元組中元素的數(shù)量
嘗試編譯這段代碼會(huì)給出如下類型錯(cuò)誤:
$ cargo run
Compiling patterns v0.1.0 (file:///projects/patterns)
error[E0308]: mismatched types
--> src/main.rs:2:9
|
2 | let (x, y) = (1, 2, 3);
| ^^^^^^ --------- this expression has type `({integer}, {integer}, {integer})`
| |
| expected a tuple with 3 elements, found one with 2 elements
|
= note: expected tuple `({integer}, {integer}, {integer})`
found tuple `(_, _)`
For more information about this error, try `rustc --explain E0308`.
error: could not compile `patterns` due to previous error
如果希望忽略元組中一個(gè)或多個(gè)值,也可以使用 _
或 ..
,如 “忽略模式中的值” 部分所示。如果問題是模式中有太多的變量,則解決方法是通過去掉變量使得變量數(shù)與元組中元素?cái)?shù)相等。
函數(shù)參數(shù)也可以是模式。列表 18-6 中的代碼聲明了一個(gè)叫做 foo
的函數(shù),它獲取一個(gè) i32
類型的參數(shù) x
,現(xiàn)在這看起來(lái)應(yīng)該很熟悉:
fn foo(x: i32) {
// code goes here
}
列表 18-6: 在參數(shù)中使用模式的函數(shù)簽名
x
部分就是一個(gè)模式!類似于之前對(duì) let
所做的,可以在函數(shù)參數(shù)中匹配元組。列表 18-7 將傳遞給函數(shù)的元組拆分為值:
文件名: src/main.rs
fn print_coordinates(&(x, y): &(i32, i32)) {
println!("Current location: ({}, {})", x, y);
}
fn main() {
let point = (3, 5);
print_coordinates(&point);
}
列表 18-7: 一個(gè)在參數(shù)中解構(gòu)元組的函數(shù)
這會(huì)打印出 Current location: (3, 5)
。值 &(3, 5)
會(huì)匹配模式 &(x, y)
,如此 x
得到了值 3
,而 y
得到了值 5
。
因?yàn)槿绲谑滤v閉包類似于函數(shù),也可以在閉包參數(shù)列表中使用模式。
現(xiàn)在我們見過了很多使用模式的方式了,不過模式在每個(gè)使用它的地方并不以相同的方式工作;在一些地方,模式必須是 irrefutable 的,意味著他們必須匹配所提供的任何值。在另一些情況,他們則可以是 refutable 的。接下來(lái)讓我們討論這兩個(gè)概念。
Copyright©2021 w3cschool編程獅|閩ICP備15016281號(hào)-3|閩公網(wǎng)安備35020302033924號(hào)
違法和不良信息舉報(bào)電話:173-0602-2364|舉報(bào)郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號(hào)
聯(lián)系方式:
更多建議: