Panics และ Unwrap
Panic คืออะไร?
หัวข้อที่มีชื่อว่า “Panic คืออะไร?”Panic คือวิธีที่ Rust บอกว่า “สถานการณ์นี้คือบั๊ก — ฉันไม่สามารถดำเนินการต่อได้อย่างปลอดภัย” เมื่อ panic เกิดขึ้น Rust จะคลายสแต็กการเรียก รัน destructor และยุติเธรดปัจจุบัน ในโปรแกรมแบบ single-thread หมายความว่าโปรเซสทั้งหมดจะออก
คุณสามารถทริกเกอร์ panic อย่างชัดเจนด้วย macro panic!:
fn main() { panic!("something went terribly wrong");}หลายการดำเนินการมาตรฐานยัง panic โดยอัตโนมัติเมื่อใช้ไม่ถูกต้อง:
fn main() { let v = vec![1, 2, 3]; println!("{}", v[10]); // index out of bounds — panic!}fn main() { let x: Option<i32> = None; let _ = x.unwrap(); // called unwrap() on a None value — panic!}.unwrap() และ .expect()
หัวข้อที่มีชื่อว่า “.unwrap() และ .expect()”.unwrap() บน Option<T> หรือ Result<T, E> ดึงค่าภายในหากเป็น Some/Ok และpanic หากเป็น None/Err เป็นทางลัดที่แลกความปลอดภัยกับความกระชับ
.expect(msg) ทำสิ่งเดียวกัน แต่ให้คุณกำหนดข้อความอธิบายที่ปรากฏในผลลัพธ์ panic ทำให้การ debug ง่ายขึ้นมาก
fn main() { let some_value: Option<i32> = Some(42); let n = some_value.unwrap(); // fine — value is Some println!("n = {}", n);
let parsed: Result<i32, _> = "99".parse(); let m = parsed.expect("input should always be a valid integer"); println!("m = {}", m);}เมื่อใดที่การ Panic เหมาะสม?
หัวข้อที่มีชื่อว่า “เมื่อใดที่การ Panic เหมาะสม?”Panic เหมาะสมเมื่อ:
- สถานการณ์แสดงถึงบั๊กในโค้ดของคุณ ไม่ใช่ความล้มเหลวของผู้ใช้หรือสภาพแวดล้อม
- คุณกำลังเขียนการทดสอบหรือโปรโตไทป์ ที่การ crash อย่างรวดเร็วมีประโยชน์
- คุณได้ตรวจสอบเงื่อนไขเบื้องต้นไว้ที่อื่นแล้ว และค่าคงที่ไม่สามารถถูกละเมิดได้จริง
Panic ไม่เหมาะสมเมื่อ:
- ความล้มเหลวสามารถมาจากอินพุตภายนอก (ไฟล์ เครือข่าย ข้อมูลผู้ใช้)
- ผู้เรียกอาจต้องการกู้คืนและลองสิ่งอื่น
- คุณกำลังเขียนโค้ดไลบรารีที่โปรแกรมอื่นเรียกใช้
ค่าเริ่มต้นที่ปลอดภัยกว่าด้วย .unwrap_or และ .unwrap_or_else
หัวข้อที่มีชื่อว่า “ค่าเริ่มต้นที่ปลอดภัยกว่าด้วย .unwrap_or และ .unwrap_or_else”เมื่อคุณต้องการค่าสำรองแทนการ panic ให้ใช้ .unwrap_or(default) หรือ .unwrap_or_else(|| compute_default())
fn safe_sqrt(n: f64) -> Result<f64, String> { if n < 0.0 { Err(format!("cannot take sqrt of negative number: {}", n)) } else { Ok(n.sqrt()) }}
fn main() { // .unwrap_or provides a default instead of panicking let a: Option<i32> = Some(42); let b: Option<i32> = None; println!("a unwrap_or: {}", a.unwrap_or(0)); println!("b unwrap_or: {}", b.unwrap_or(0));
// .expect gives a custom panic message (use only when failure is a bug) let good = safe_sqrt(16.0).expect("sqrt should not fail on positive numbers"); println!("sqrt(16) = {}", good);
// .unwrap_or_else with a closure for recoverable defaults let result = safe_sqrt(-4.0).unwrap_or_else(|e| { println!("Handled: {}", e); 0.0 }); println!("result = {}", result);}Compiling…