Common Standard Macros
panic!
The panic! macro immediately terminates the normal execution of the current thread with a formatted diagnostic message, source file, and line number, either unwinding the thread's call stack (executing Drop destructors along the way) or aborting the process.
Syntactic Forms and the Never Type (!)
| Invocation Form | Example | Panic Message Produced |
|---|---|---|
| No arguments | panic!() |
"explicit panic" |
| String literal | panic!("invariant violated") |
"invariant violated" |
| Formatted arguments | panic!("index {idx} out of bounds (len = {len})") |
Interpolated format_args! string |
Because panic! never returns to its caller, its return type is the never type (!), which coerces to any type T in match arms, if / else branches, or functions returning a value:
fn parse_required_env(key: &str, value: Option<&str>) -> String {
match value {
Some(v) if !v.is_empty() => v.to_owned(),
// `panic!` has type `!`, which coerces to `String`:
_ => panic!("required environment variable `{key}` is missing or empty"),
}
}
fn main() {
let db_url = parse_required_env("DATABASE_URL", Some("postgres://localhost/app"));
println!("Connected to {db_url}");
}
Connected to postgres://localhost/app
What Happens When panic! Runs
panic!("fatal state: {code}")
│
▼ 1. Invokes the global panic hook (prints message, file:line:col, and backtrace if `RUST_BACKTRACE=1`)
│
├── Default (`panic = "unwind"`):
│ Walks up the thread stack frame by frame, running `Drop::drop` on every live local variable
│ (If inside a spawned thread, `JoinHandle::join()` catches the unwind and returns `Err(payload)`)
│
└── Configured (`panic = "abort"` in Cargo.toml):
Immediately terminates the OS process without unwinding the stack
Example panic output on standard error:
fn main() {
let port = 0_u16;
if port == 0 {
panic!("invalid listening port: {port}");
}
}
thread 'main' panicked at src/main.rs:4:9:
invalid listening port: 0
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace