Panics: When Things Go Catastrophically Wrong
Rust has two categories of errors: recoverable (Result/Option) and unrecoverable (panic). Panics are for bugs - things that should never happen.
fn main() {
// Direct panic
// panic!("Something went terribly wrong");
// Panics from invalid operations
let v = vec![1, 2, 3];
// v[10]; // index out of bounds - panics!
// 5 / 0; // integer division by zero - panics!
// unwrap and expect panic on None/Err
let x: Option = None;
// x.unwrap(); // called `Option::unwrap()` on a `None` value
// x.expect("x should always be Some"); // Better panic message
// Use panic for programming errors, not user errors:
fn divide(a: i32, b: i32) -> i32 {
assert!(b != 0, "Division by zero is a programming error");
a / b
}
// Catching panics (rarely needed - prefer Result)
use std::panic;
let result = panic::catch_unwind(|| {
42 // or: panic!("oops")
});
println!("{:?}", result); // Ok(42)
// In tests, you can assert panics:
// #[should_panic(expected = "divide by zero")]
// fn test_divide_by_zero() { divide(1, 0); }
} When to Panic
// PANIC when: it is a programming error (impossible state)
fn get_first(v: &[i32]) -> i32 {
assert!(!v.is_empty(), "Cannot get first of empty slice");
v[0]
}
// RETURN Result when: it is a user/runtime error (expected to happen)
fn parse_config(s: &str) -> Result {
s.trim().parse::().map_err(|e| format!("Invalid port: {}", e))
}
// Useful assertion macros:
fn assertions_demo() {
assert!(1 + 1 == 2);
assert_eq!(4, 2 + 2);
assert_ne!(5, 2 + 2);
assert!(true, "Optional message: {}", "with formatting");
debug_assert!(1 == 1); // Only in debug builds, optimized away in release
} 🎯 Practice
- Write a function that panics with a clear message when given negative input
- Use assert_eq! and assert_ne! in a test function (with #[test])
- Use panic::catch_unwind to test that a function panics in specific conditions
🎉 Key Takeaways
- panic! is for bugs; Result is for expected failure conditions
- assert!, assert_eq!, assert_ne! panic with descriptive messages
- unwrap/expect are fine in tests and prototypes; avoid in production code
- debug_assert! is free in release builds - use for expensive invariant checks