控制流程
YouTube 上觀看本章內容: Part 1 及 Part 2
控制流程(control flow)的意思是告訴你的程式碼在不同的情況下該怎麼做。最簡單的控制流程是 if
。
fn main() { let my_number = 5; if my_number == 7 { println!("It's seven"); } }
另外注意,你用的是 ==
而不是 =
。==
是用來比較的,=
是用來賦值的(給一個值)。另外注意,我們寫的是 if my_number == 7
而不是 if (my_number == 7)
。在 Rust 中,你不需要在 if
條件用括號。
else if
和 else
給你更多的控制:
fn main() { let my_number = 5; if my_number == 7 { println!("It's seven"); } else if my_number == 6 { println!("It's six") } else { println!("It's a different number") } }
印出 It's a different number
,因為它不等於 7 或 6。
您可以使用 &&
(和)和 ||
(或)來新增更多條件。
fn main() { let my_number = 5; if my_number % 2 == 1 && my_number > 0 { // % 2 表示除以2之後的餘下的數 println!("It's a positive odd number"); } else if my_number == 6 { println!("It's six") } else { println!("It's a different number") } }
印出 It's a positive odd number
,因為當你把它除以 2 時,你有餘數 1,且它大於0。
你可以看到,過多的 if
、else
和 else if
會很難讀。在這種情況下,你可以使用 match
來代替,它看起來更乾淨。但是您必須為每一個可能的結果進行匹配(match)。例如,這將無法運作:
fn main() { let my_number: u8 = 5; match my_number { 0 => println!("it's zero"), 1 => println!("it's one"), 2 => println!("it's two"), // ⚠️ } }
編譯器說:
error[E0004]: non-exhaustive patterns: `3u8..=std::u8::MAX` not covered
--> src\main.rs:3:11
|
3 | match my_number {
| ^^^^^^^^^ pattern `3u8..=std::u8::MAX` not covered
這就意味著"你告訴我 0 到 2,但 u8
可以到 255。那 3 呢?4 呢?5 呢?"以此類推。所以你可以加上 _
,意思是"其他任何東西"。
fn main() { let my_number: u8 = 5; match my_number { 0 => println!("it's zero"), 1 => println!("it's one"), 2 => println!("it's two"), _ => println!("It's some other number"), } }
印出 It's some other number
。
記住這些匹配的規則:
- 你寫下
match
,然後做一個{}
程式碼區塊。 - 在左邊寫上模式,用
=>
胖箭頭說明匹配時該怎麼做。 - 每一行稱為一個"分支(arm)"。
- 在分支之間放一個逗號(不是分號)。
你可以用匹配結果來宣告一個值:
fn main() { let my_number = 5; let second_number = match my_number { 0 => 0, 5 => 10, _ => 2, }; }
second_number
將是 10。你看到最後的分號了嗎?那是因為,在 match 結束後,我們實際上告訴了編譯器這個資訊:let second_number = 10;
你也可以在更復雜的事情上進行匹配。你要用元組來做到。
fn main() { let sky = "cloudy"; let temperature = "warm"; match (sky, temperature) { ("cloudy", "cold") => println!("It's dark and unpleasant today"), ("clear", "warm") => println!("It's a nice day"), ("cloudy", "warm") => println!("It's dark but not bad"), _ => println!("Not sure what the weather is."), } }
印出 It's dark but not bad
,因為它與 sky
和 temperature
的 "cloudy" 和 "warm" 相匹配。
你甚至可以把 if
放在 match
裡面。這稱為 "match guard":
fn main() { let children = 5; let married = true; match (children, married) { (children, married) if married == false => println!("Not married with {} children", children), (children, married) if children == 0 && married == true => println!("Married but no children"), _ => println!("Married? {}. Number of children: {}.", married, children), } }
這將印出 Married? true. Number of children: 5.
在匹配時,你可以隨意多次使用 _。在這個關於顏色的匹配中,我們有三個顏色,但一次只能選中一個。
fn match_colours(rbg: (i32, i32, i32)) { match rbg { (r, _, _) if r < 10 => println!("Not much red"), (_, b, _) if b < 10 => println!("Not much blue"), (_, _, g) if g < 10 => println!("Not much green"), _ => println!("Each colour has at least 10"), } } fn main() { let first = (200, 0, 0); let second = (50, 50, 50); let third = (200, 50, 0); match_colours(first); match_colours(second); match_colours(third); }
印出:
Not much blue
Each colour has at least 10
Not much green
這也說明了 match
陳述式的作用,因為在第一個例子中,它只印了 Not much blue
。但是 first
也沒有多少綠色。match
陳述式總是在找到一個匹配項時停止,而不檢查其他的。這就是程式碼編譯得很好,但不是你想要的程式碼的一個好例子。
你可以做一個非常大的 match
陳述式來解決這個問題,但是使用 for
迴圈(loop)可能更好。我們將很快會討論到迴圈。
匹配必須回傳相同的型別。所以你不能這樣做:
fn main() { let my_number = 10; let some_variable = match my_number { 10 => 8, _ => "Not ten", // ⚠️ }; }
編譯器告訴你:
error[E0308]: `match` arms have incompatible types
--> src\main.rs:17:14
|
15 | let some_variable = match my_number {
| _________________________-
16 | | 10 => 8,
| | - this is found to be of type `{integer}`
17 | | _ => "Not ten",
| | ^^^^^^^^^ expected integer, found `&str`
18 | | };
| |_____- `match` arms have incompatible types
這樣也不行,原因同上。
fn main() { let some_variable = if my_number == 10 { 8 } else { "something else "}; // ⚠️ }
但是這樣就可以了,因為不是 match
,所以你每次都有不同的 let
陳述式:
fn main() { let my_number = 10; if my_number == 10 { let some_variable = 8; } else { let some_variable = "Something else"; } }
你也可以使用 @
給 match
表示式的值命名,然後你就可以使用它。在這個範例中,我們在函式中匹配 i32
輸入。如果是 4 或 13,我們要在 println!
陳述式中使用這個數字。否則,我們不需要使用它。
fn match_number(input: i32) { match input { number @ 4 => println!("{} is an unlucky number in China (sounds close to 死)!", number), number @ 13 => println!("{} is unlucky in North America, lucky in Italy! In bocca al lupo!", number), _ => println!("Looks like a normal number"), } } fn main() { match_number(50); match_number(13); match_number(4); }
印出:
Looks like a normal number
13 is unlucky in North America, lucky in Italy! In bocca al lupo!
4 is an unlucky number in China (sounds close to 死)!