Refutability — Pattern อาจ Fail ในการ Match ไหม
Pattern มีสองรูปแบบ — refutable และ irrefutable Pattern ที่จะ match
สำหรับค่าที่เป็นไปได้ใดที่ส่งคือ irrefutable ตัวอย่างจะเป็น x ใน
statement let x = 5; เพราะ x match อะไรก็ได้และดังนั้นไม่ fail ใน
การ match Pattern ที่ fail ในการ match สำหรับค่าที่เป็นไปได้บางอย่างคือ
refutable ตัวอย่างจะเป็น Some(x) ใน expression if let Some(x) = a_value เพราะถ้าค่าในตัวแปร a_value คือ None แทนที่จะเป็น Some
pattern Some(x) จะไม่ match
Parameter ฟังก์ชัน, statement let และ loop for รับเพียง pattern
irrefutable เพราะโปรแกรมไม่สามารถทำอะไรที่มีความหมายเมื่อค่าไม่ match
Expression if let และ while let และ statement let...else รับทั้ง
pattern refutable และ irrefutable แต่ compiler เตือนต่อ pattern
irrefutable เพราะตามนิยาม พวกมันตั้งใจจัดการ failure ที่เป็นไปได้ —
functionality ของ conditional คือในความสามารถของมันที่จะทำต่างขึ้นกับ
success หรือ failure
โดยทั่วไป คุณไม่ต้องกังวลเกี่ยวกับความแตกต่างระหว่าง pattern refutable และ irrefutable; อย่างไรก็ตาม คุณต้องคุ้นเคยกับแนวคิดของ refutability เพื่อให้คุณตอบสนองได้เมื่อคุณเห็นมันในข้อความ error ในกรณีเหล่านั้น คุณจะต้องเปลี่ยนทั้ง pattern หรือ construct ที่คุณใช้ pattern กับ ขึ้นกับพฤติกรรมที่ตั้งใจของโค้ด
มาดูตัวอย่างของสิ่งที่เกิดขึ้นเมื่อเราพยายามใช้ pattern refutable ที่
Rust ต้องการ pattern irrefutable และในทางกลับกัน Listing 19-8 แสดง
statement let แต่สำหรับ pattern เราระบุ Some(x), pattern refutable
ดังที่คุณคาดเดา โค้ดนี้จะไม่ compile
fn main() {
let some_option_value: Option<i32> = None;
let Some(x) = some_option_value;
}
letถ้า some_option_value เป็นค่า None มันจะ fail ในการ match pattern
Some(x) หมายความว่า pattern เป็น refutable อย่างไรก็ตาม statement
let รับเพียง pattern irrefutable ได้เพราะไม่มีอะไร valid ที่โค้ดทำกับ
ค่า None ได้ ที่ compile time Rust จะบ่นว่าเราพยายามใช้ pattern
refutable ที่ pattern irrefutable ถูกต้องการ:
$ cargo run
Compiling patterns v0.1.0 (file:///projects/patterns)
error[E0005]: refutable pattern in local binding
--> src/main.rs:3:9
|
3 | let Some(x) = some_option_value;
| ^^^^^^^ pattern `None` not covered
|
= note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
= note: for more information, visit https://doc.rust-lang.org/book/ch19-02-refutability.html
= note: the matched value is of type `Option<i32>`
help: you might want to use `let else` to handle the variant that isn't matched
|
3 | let Some(x) = some_option_value else { todo!() };
| ++++++++++++++++
For more information about this error, try `rustc --explain E0005`.
error: could not compile `patterns` (bin "patterns") due to 1 previous error
เพราะเราไม่ครอบคลุม (และไม่สามารถครอบคลุม!) ทุกค่า valid กับ pattern
Some(x) Rust ผลิต error compiler อย่างถูกต้อง
ถ้าเรามี pattern refutable ที่ pattern irrefutable ถูกต้องการ เรา fix
มันโดยเปลี่ยนโค้ดที่ใช้ pattern ได้ — แทนที่จะใช้ let เราใช้
let...else ได้ แล้ว ถ้า pattern ไม่ match โค้ดใน curly bracket จะ
จัดการค่า Listing 19-9 แสดงวิธี fix โค้ดใน Listing 19-8
fn main() {
let some_option_value: Option<i32> = None;
let Some(x) = some_option_value else {
return;
};
}
let...else และ block กับ pattern refutable แทน letเราให้โค้ดทางออก! โค้ดนี้ valid อย่างสมบูรณ์ แม้มันหมายความว่าเราไม่
สามารถใช้ pattern irrefutable โดยไม่รับ warning ถ้าเราให้ let...else
pattern ที่จะ match เสมอ เช่น x ดังที่แสดงใน Listing 19-10 compiler
จะให้ warning
fn main() {
let x = 5 else {
return;
};
}
let...elseRust บ่นว่ามันไม่สมเหตุสมผลที่จะใช้ let...else กับ pattern
irrefutable:
$ cargo run
Compiling patterns v0.1.0 (file:///projects/patterns)
warning: irrefutable `let...else` pattern
--> src/main.rs:2:5
|
2 | let x = 5 else {
| ^^^^^^^^^
|
= note: this pattern will always match, so the `else` clause is useless
= help: consider removing the `else` clause
= note: `#[warn(irrefutable_let_patterns)]` on by default
warning: `patterns` (bin "patterns") generated 1 warning
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.39s
Running `target/debug/patterns`
เพราะเหตุผลนี้ match arm ต้องใช้ pattern refutable ยกเว้น arm สุดท้าย
ซึ่งควร match ค่าที่เหลือใดกับ pattern irrefutable Rust อนุญาตให้เรา
ใช้ pattern irrefutable ใน match กับเพียงหนึ่ง arm ได้ แต่ syntax นี้
ไม่มีประโยชน์เป็นพิเศษและถูกแทนที่ด้วย statement let ที่ง่ายกว่าได้
ตอนนี้คุณรู้ที่จะใช้ pattern และความแตกต่างระหว่าง pattern refutable และ irrefutable มาครอบคลุม syntax ทั้งหมดที่เราใช้สร้าง pattern ได้