สนิม - การจัดการข้อผิดพลาด
ใน Rust ข้อผิดพลาดสามารถแบ่งออกเป็นสองประเภทใหญ่ ๆ ดังแสดงในตารางด้านล่าง
ซีเนียร์ No | ชื่อและคำอธิบาย | การใช้งาน |
---|---|---|
1 | Recoverable ข้อผิดพลาดที่สามารถจัดการได้ |
ผลลัพธ์ enum |
2 | UnRecoverable ข้อผิดพลาดที่ไม่สามารถจัดการได้ |
มาโครตื่นตระหนก |
ข้อผิดพลาดที่สามารถกู้คืนได้คือข้อผิดพลาดที่สามารถแก้ไขได้ โปรแกรมสามารถลองดำเนินการที่ล้มเหลวอีกครั้งหรือระบุแนวทางการดำเนินการอื่นเมื่อพบข้อผิดพลาดที่สามารถกู้คืนได้ ข้อผิดพลาดที่สามารถกู้คืนได้ไม่ทำให้โปรแกรมล้มเหลวในทันที ตัวอย่างของข้อผิดพลาดที่คาดว่าจะไม่พบไฟล์ข้อผิดพลาด
ข้อผิดพลาดที่ไม่สามารถกู้คืนได้ทำให้โปรแกรมล้มเหลวทันที โปรแกรมไม่สามารถเปลี่ยนกลับสู่สถานะปกติได้หากเกิดข้อผิดพลาดที่ไม่สามารถกู้คืนได้ ไม่สามารถลองอีกครั้งการดำเนินการที่ล้มเหลวหรือยกเลิกข้อผิดพลาด ตัวอย่างของข้อผิดพลาดที่ไม่สามารถกู้คืนได้พยายามเข้าถึงตำแหน่งที่อยู่นอกเหนือจากจุดสิ้นสุดของอาร์เรย์
ไม่เหมือนกับภาษาโปรแกรมอื่น ๆ Rust ไม่มีข้อยกเว้น จะส่งคืน enum Result <T, E>สำหรับข้อผิดพลาดที่สามารถกู้คืนได้ในขณะที่มันเรียกpanicแมโครหากโปรแกรมพบข้อผิดพลาดที่ไม่สามารถกู้คืนได้ ตื่นตระหนกแมโครทำให้โปรแกรมเพื่อออกทันที
Panic Macro และข้อผิดพลาดที่ไม่สามารถกู้คืนได้
ตื่นตกใจ! มาโครช่วยให้โปรแกรมยุติทันทีและให้ข้อเสนอแนะแก่ผู้เรียกโปรแกรม ควรใช้เมื่อโปรแกรมถึงสถานะที่ไม่สามารถกู้คืนได้
fn main() {
panic!("Hello");
println!("End of main"); //unreachable statement
}
ในตัวอย่างข้างต้นโปรแกรมจะยุติทันทีเมื่อพบกับความตื่นตระหนก! มาโคร
เอาต์พุต
thread 'main' panicked at 'Hello', main.rs:3
ภาพประกอบ: ตกใจ! มาโคร
fn main() {
let a = [10,20,30];
a[10]; //invokes a panic since index 10 cannot be reached
}
เอาต์พุตดังแสดงด้านล่าง -
warning: this expression will panic at run-time
--> main.rs:4:4
|
4 | a[10];
| ^^^^^ index out of bounds: the len is 3 but the index is 10
$main
thread 'main' panicked at 'index out of bounds: the len
is 3 but the index is 10', main.rs:4
note: Run with `RUST_BACKTRACE=1` for a backtrace.
โปรแกรมสามารถทำให้ตื่นตระหนก! macro หากละเมิดกฎทางธุรกิจดังที่แสดงในตัวอย่างด้านล่าง -
fn main() {
let no = 13;
//try with odd and even
if no%2 == 0 {
println!("Thank you , number is even");
} else {
panic!("NOT_AN_EVEN");
}
println!("End of main");
}
ตัวอย่างข้างต้นส่งกลับข้อผิดพลาดหากค่าที่กำหนดให้กับตัวแปรเป็นเลขคี่
เอาต์พุต
thread 'main' panicked at 'NOT_AN_EVEN', main.rs:9
note: Run with `RUST_BACKTRACE=1` for a backtrace.
ผลลัพธ์ Enum และข้อผิดพลาดที่กู้คืนได้
Enum Result - <T, E> สามารถใช้เพื่อจัดการกับข้อผิดพลาดที่สามารถกู้คืนได้ มีสองสายพันธุ์ -OK และ Err. T และ E เป็นพารามิเตอร์ประเภททั่วไป T แสดงถึงชนิดของค่าที่จะส่งคืนในกรณีความสำเร็จภายในตัวแปร OK และ E แสดงถึงประเภทของข้อผิดพลาดที่จะส่งคืนในกรณีความล้มเหลวภายในตัวแปร Err
enum Result<T,E> {
OK(T),
Err(E)
}
ให้เราเข้าใจสิ่งนี้ด้วยความช่วยเหลือของตัวอย่าง -
use std::fs::File;
fn main() {
let f = File::open("main.jpg");
//this file does not exist
println!("{:?}",f);
}
โปรแกรมจะส่งคืนOK (File)หากไฟล์มีอยู่แล้วและErr (Error)หากไม่พบไฟล์
Err(Error { repr: Os { code: 2, message: "No such file or directory" } })
ตอนนี้ให้เราดูวิธีจัดการตัวแปร Err
ตัวอย่างต่อไปนี้จัดการข้อผิดพลาดที่ส่งคืนขณะเปิดไฟล์โดยใช้ match คำให้การ
use std::fs::File;
fn main() {
let f = File::open("main.jpg"); // main.jpg doesn't exist
match f {
Ok(f)=> {
println!("file found {:?}",f);
},
Err(e)=> {
println!("file not found \n{:?}",e); //handled error
}
}
println!("end of main");
}
NOTE- โปรแกรมพิมพ์จุดสิ้นสุดของเหตุการณ์หลักแม้ว่าจะไม่พบไฟล์ ซึ่งหมายความว่าโปรแกรมได้จัดการข้อผิดพลาดอย่างสง่างาม
เอาต์พุต
file not found
Os { code: 2, kind: NotFound, message: "The system cannot find the file specified." }
end of main
ภาพประกอบ
is_evenฟังก์ชันส่งกลับข้อผิดพลาดหากหมายเลขที่ไม่ได้เป็นเลขคู่ ฟังก์ชัน main () จัดการข้อผิดพลาดนี้
fn main(){
let result = is_even(13);
match result {
Ok(d)=>{
println!("no is even {}",d);
},
Err(msg)=>{
println!("Error msg is {}",msg);
}
}
println!("end of main");
}
fn is_even(no:i32)->Result<bool,String> {
if no%2==0 {
return Ok(true);
} else {
return Err("NOT_AN_EVEN".to_string());
}
}
NOTE- เนื่องจากฟังก์ชั่นหลักจัดการกับข้อผิดพลาดอย่างสง่างามส่วนท้ายของคำสั่งหลักจึงถูกพิมพ์ออกมา
เอาต์พุต
Error msg is NOT_AN_EVEN
end of main
แกะ () และคาดหวัง ()
ไลบรารีมาตรฐานมีตัวช่วยสองสามวิธีที่ทั้งสอง enums - ผลลัพธ์<T, E>และตัวเลือก<T>นำไปใช้ คุณสามารถใช้เพื่อลดความซับซ้อนของกรณีข้อผิดพลาดโดยที่คุณไม่คาดหวังว่าสิ่งต่างๆจะล้มเหลว ในกรณีที่ประสบความสำเร็จจากวิธีการหนึ่งฟังก์ชัน "แกะ" จะถูกใช้เพื่อดึงผลลัพธ์ที่แท้จริงออกมา
ซีเนียร์ No | วิธี | ลายเซ็นและคำอธิบาย |
---|---|---|
1 | แกะ | unwrap(self): T คาดหวังให้ตัวเองเป็น Ok / Some และส่งคืนค่าที่อยู่ภายใน ถ้ามันเป็นErr หรือ None แต่กลับสร้างความตื่นตระหนกกับเนื้อหาของข้อผิดพลาดที่ปรากฏขึ้น |
2 | คาดหวัง | expect(self, msg: &str): T ทำตัวเหมือนแกะออกยกเว้นว่าจะส่งออกข้อความที่กำหนดเองก่อนที่จะตื่นตระหนกนอกเหนือไปจากเนื้อหาของข้อผิดพลาด |
แกะ()
ฟังก์ชันแกะ () ส่งคืนผลลัพธ์จริงที่การดำเนินการสำเร็จ ส่งคืนความตื่นตระหนกพร้อมข้อความแสดงข้อผิดพลาดเริ่มต้นหากการดำเนินการล้มเหลว ฟังก์ชันนี้เป็นชวเลขสำหรับคำสั่งจับคู่ สิ่งนี้แสดงในตัวอย่างด้านล่าง -
fn main(){
let result = is_even(10).unwrap();
println!("result is {}",result);
println!("end of main");
}
fn is_even(no:i32)->Result<bool,String> {
if no%2==0 {
return Ok(true);
} else {
return Err("NOT_AN_EVEN".to_string());
}
}
result is true
end of main
แก้ไขรหัสด้านบนเพื่อส่งตัวเลขคี่ไปยังไฟล์ is_even() ฟังก์ชัน
ฟังก์ชันแกะ ()จะตื่นตระหนกและส่งกลับข้อความแสดงข้อผิดพลาดเริ่มต้นดังที่แสดงด้านล่าง
thread 'main' panicked at 'called `Result::unwrap()` on
an `Err` value: "NOT_AN_EVEN"', libcore\result.rs:945:5
note: Run with `RUST_BACKTRACE=1` for a backtrace
คาดหวัง ()
โปรแกรมสามารถส่งคืนข้อความแสดงข้อผิดพลาดที่กำหนดเองในกรณีที่เกิดความตื่นตระหนก สิ่งนี้แสดงในตัวอย่างต่อไปนี้ -
use std::fs::File;
fn main(){
let f = File::open("pqr.txt").expect("File not able to open");
//file does not exist
println!("end of main");
}
ฟังก์ชัน expect () คล้ายกับการแกะ () ข้อแตกต่างเพียงอย่างเดียวคือข้อความแสดงข้อผิดพลาดที่กำหนดเองสามารถแสดงได้โดยใช้การคาดหวัง
เอาต์พุต
thread 'main' panicked at 'File not able to open: Error { repr: Os
{ code: 2, message: "No such file or directory" } }', src/libcore/result.rs:860
note: Run with `RUST_BACKTRACE=1` for a backtrace.