panic! - Unrecoverable Errors
panic! หยุดโปรแกรมทันทีเมื่อเกิด error ที่จัดการไม่ได้
🚨 Error Handling Decision Tree
+-------------------------------------------------------------------+
| Error Handling in Rust |
+-------------------------------------------------------------------+
| |
| +--------------+ |
| | Error occurs | |
| +------+-------+ |
| | |
| +-----------------+-----------------+ |
| | | |
| v v |
| +---------------+ +---------------+ |
| | Recoverable? | | Unrecoverable | |
| | Can recover | | Cannot recover| |
| +-------+-------+ +-------+-------+ |
| | | |
| v v |
| +---------------+ +---------------+ |
| | Result<T, E> | | panic!() | |
| | | | | |
| | * File not | | * Bug in code | |
| | found | | * Impossible | |
| | * Parse error | | state | |
| | * Network | | * Contract | |
| | timeout | | violation | |
| +---------------+ +---------------+ |
| |
+-------------------------------------------------------------------+
เมื่อไหร่เกิด Panic?
1. เรียก panic! เอง
fn main() {
panic!("crash and burn");
}
Output:
thread 'main' panicked at 'crash and burn', src/main.rs:2:5
2. Bug ในโค้ด
fn main() {
let v = vec![1, 2, 3];
v[99]; // 💥 panic! index out of bounds
}
Backtrace
ดู backtrace เพื่อหาที่มาของ panic:
RUST_BACKTRACE=1 cargo run
```text
```text
thread 'main' panicked at 'index out of bounds: the len is 3 but the index is 99'
stack backtrace:
0: std::panicking::begin_panic_handler
1: core::panicking::panic_bounds_check
2: <usize as core::slice::SliceIndex<[T]>>::index
3: playground::main
at src/main.rs:3:5
เมื่อไหร่ควรใช้ panic!
✅ ควรใช้
- Prototyping - ตัวอย่างโค้ด, ทดลอง
fn main() {
// ยังไม่ได้ implement
todo!("implement this later");
}
- Tests - เมื่อ test fail
#[test]
fn test_something() {
assert_eq!(1, 2); // panic! ถ้าไม่เท่า
}
- Unrecoverable situation - สถานการณ์ที่โปรแกรมต้องหยุด
#![allow(unused)]
fn main() {
fn divide(a: i32, b: i32) -> i32 {
if b == 0 {
panic!("Cannot divide by zero!");
}
a / b
}
}
- Invalid state - ข้อมูลอยู่ในสถานะที่ไม่ถูกต้อง
#![allow(unused)]
fn main() {
fn process_age(age: i32) {
if age < 0 || age > 150 {
panic!("Invalid age: {}", age);
}
// ...
}
}
❌ ไม่ควรใช้
- Expected failures - เช่น file not found, network error
- User input errors - ผู้ใช้พิมพ์ผิด
- Recoverable errors - ลอง retry ได้
Rule of thumb: ถ้าผู้เรียกสามารถ handle error ได้ → ใช้
Result
💡 Best Practices: panic! vs Result
+---------------------------------------------------------+ | Error Handling Choice | +---------------------------------------------------------+ | panic! | Result<T, E> | +-------------------+-------------------------------------+ | * Bug in code | * File not found | | * Invalid state | * Network error | | * Tests | * User input error | | * Prototyping | * Parse error | | * Unrecoverable | * Recoverable errors | +-------------------+-------------------------------------+
unwrap และ expect
unwrap
fn main() {
let x: Option<i32> = Some(5);
let value = x.unwrap(); // ✅ 5
let y: Option<i32> = None;
// let value = y.unwrap(); // 💥 panic!
}
expect (ดีกว่า unwrap)
fn main() {
let x: Option<i32> = None;
// ให้ error message ที่ชัดเจน
let value = x.expect("x should have a value");
}
Output:
thread 'main' panicked at 'x should have a value', src/main.rs:4:18
unreachable! และ todo!
fn main() {
let level = 5;
let description = match level {
1..=5 => "beginner",
6..=10 => "intermediate",
11..=20 => "advanced",
_ => unreachable!("level should be 1-20"),
};
// ยังไม่ได้ implement
todo!("add more logic here");
}
ตัวอย่างจริง: Assertion
fn set_age(age: u32) {
assert!(age <= 150, "Age {} is unrealistic", age);
println!("Age set to {}", age);
}
fn main() {
set_age(25); // ✅ OK
set_age(200); // 💥 panic!
}
ลองทำดู! 🎯
- สร้าง function ที่ panic เมื่อได้รับค่าลบ
- ใช้ expect แทน unwrap และให้ error message ที่ดี
- ลองเปิด RUST_BACKTRACE=1 ดู backtrace
สรุป
| Macro | ใช้เมื่อ |
|---|---|
panic!("msg") | Error ร้ายแรง |
unreachable!() | โค้ดที่ไม่ควรถูกเรียก |
todo!() | ยังไม่ได้ implement |
assert!(cond) | ตรวจสอบเงื่อนไข |
👉 ต่อไป: Result<T, E>