ข้ามไปยังเนื้อหา

Pattern Matching

match เปรียบเทียบค่ากับชุด pattern และ execute arm ที่ pattern ตรงกัน ต่างจาก switch ใน C, match ของ Rust เป็น expression — สร้างค่าออกมา — และคอมไพเลอร์ตรวจสอบความครบถ้วน

let x: i32 = 3;
let description = match x {
1 => "one",
2 => "two",
3 => "three",
_ => "something else",
};
println!("{}", description); // three

Pattern _ จับคู่กับค่าใดก็ตามที่คุณยังไม่ได้ระบุ หากไม่มี (และไม่ครอบคลุมทุกกรณี) โค้ดจะไม่ compile

พลังที่แท้จริงของ match มาจากการ destructure enum variant และ bind ข้อมูลของตัวเองกับชื่อ local:

enum Coin {
Penny,
Quarter(String),
}
match coin {
Coin::Penny => println!("Penny"),
Coin::Quarter(state) => println!("Quarter from {}", state),
}

ตัวระบุ state ใน Coin::Quarter(state) คือ binding — รับค่า String ที่ variant นั้นพกมา แล้วคุณใช้ค่านั้นได้อย่างอิสระในส่วนของ arm

Pattern สามารถจับคู่ช่วงของจำนวนเต็มด้วย ..=:

match score {
90..=100 => "A",
80..=89 => "B",
_ => "C or below",
}

_ เป็น catch-all ที่จับคู่กับทุกอย่างโดยไม่ bind วางไว้ท้ายสุด arm ใดๆ หลัง _ จะ unreachable และคอมไพเลอร์จะเตือน

เมื่อคุณสนใจแค่ variant เดียว if let กระชับกว่า match แบบเต็ม:

let temperature = Some(22);
if let Some(t) = temperature {
println!("Temperature: {}C", t);
}

นี่ bind t กับค่าภายในหาก pattern ตรงกัน และไม่ทำอะไรกับ None คุณสามารถต่อ else สำหรับกรณีที่ไม่ตรง

Guard คือเงื่อนไข if พิเศษบน match arm ที่จำกัดค่าที่ arm จะรับ:

match number {
n if n < 0 => println!("negative: {}", n),
0 => println!("zero"),
n => println!("positive: {}", n),
}

Guard ทำงานหลังจาก structural pattern ตรงกันแล้ว ดังนั้น binding (n) จึงใช้ได้ภายในเงื่อนไข guard

#[derive(Debug)]
enum Coin {
Penny,
Nickel,
Dime,
Quarter(String),
}
fn value_in_cents(coin: &Coin) -> u32 {
match coin {
Coin::Penny => 1,
Coin::Nickel => 5,
Coin::Dime => 10,
Coin::Quarter(state) => {
println!("Quarter from {}!", state);
25
}
}
}
fn describe_number(n: i32) -> &'static str {
match n {
0 => "zero",
1..=9 => "single digit",
10..=99 => "double digit",
_ => "large",
}
}
fn main() {
let coins = vec![
Coin::Penny,
Coin::Nickel,
Coin::Quarter(String::from("Alaska")),
Coin::Dime,
];
for coin in &coins {
println!("{:?} = {} cents", coin, value_in_cents(coin));
}
for n in [0, 7, 42, 100] {
println!("{} is {}", n, describe_number(n));
}
let temperature = Some(22);
if let Some(t) = temperature {
println!("Temperature: {}C", t);
}
}
จะเกิดอะไรขึ้นหาก match expression ไม่ครอบคลุมค่าที่เป็นไปได้ทั้งหมดของประเภทที่จับคู่?
pattern _ ใน match arm ทำอะไร?
ควรใช้ if let แทน match แบบเต็มเมื่อใด?
match guard คืออะไร?