What is the difference between panic! and returning a Result in Rust?
Understand when to use panic! versus returning a Result in Rust for recoverable and unrecoverable errors, with examples and interview-ready guidance.
Expected Interview Answer
panic! signals an unrecoverable error that unwinds or aborts the current thread, while returning a Result models a recoverable error as a value the caller must handle. Use panic! for bugs and broken invariants; use Result for expected failures like missing files or bad input.
A Result<T, E> makes failure part of a function's type signature, forcing callers to decide how to handle the Err case via match, the ? operator, or combinators. panic! instead aborts normal control flow: by default it unwinds the stack running destructors, then terminates the thread, which can bring down the whole program. Idiomatic Rust reserves panics for programmer errors and truly impossible states, and returns Result for anything a caller could reasonably recover from.
- Result forces explicit, compiler-checked error handling
- Errors become part of the API contract via the type
- The ? operator propagates errors cleanly
- panic! clearly marks unrecoverable bugs and invariants
- Keeps recoverable failures from silently terminating the program
AI Mentor Explanation
Returning a Result is like a fielder appealing for a wicket and letting the umpire decide, or continuing play if the decision is not out — the game absorbs the outcome and carries on. A panic! is like the floodlights failing entirely: play stops immediately, everyone leaves the field, and the match cannot continue until the fundamental problem is fixed.
Step-by-Step Explanation
Step 1
Classify the error
Decide whether the failure is recoverable (bad input, missing file) or a bug that violates an invariant.
Step 2
Model recoverable errors
Return Result<T, E> so the failure is a value the caller must acknowledge and handle.
Step 3
Propagate with ?
Use the ? operator to bubble Err upward cleanly instead of nesting match blocks.
Step 4
Reserve panic! for bugs
Call panic!, unwrap, or expect only where an error means the program's assumptions are broken.
Step 5
Configure unwinding
Choose panic = 'unwind' (runs destructors) or 'abort' (smaller binary, immediate exit) in Cargo.toml as needed.
What Interviewer Expects
- Recoverable versus unrecoverable error distinction
- Result as a type-level contract
- Knowledge of the ? operator
- When panic! is actually appropriate
- Awareness of unwind versus abort behavior
Common Mistakes
- Using unwrap everywhere instead of handling Result
- Panicking on expected, recoverable failures
- Thinking panic! is caught like a try/catch exception
- Ignoring the Err variant of a returned Result
- Not knowing panic can unwind or abort
Best Answer (HR Friendly)
“Returning a Result means a function reports failure as a value the caller has to deal with, so the program keeps running gracefully. A panic! is for serious bugs where continuing makes no sense, so it stops the thread or program instead.”
Code Example
use std::fs;
use std::io;
fn read_config(path: &str) -> Result<String, io::Error> {
let contents = fs::read_to_string(path)?; // ? propagates the Err
Ok(contents)
}
fn main() {
match read_config("config.toml") {
Ok(text) => println!("Loaded {} bytes", text.len()),
Err(e) => eprintln!("Could not load config: {e}"),
}
}fn divide(a: i32, b: i32) -> i32 {
if b == 0 {
panic!("divide called with b == 0, a broken invariant");
}
a / b
}Follow-up Questions
- How does the ? operator work under the hood?
- When is calling unwrap acceptable?
- What is the difference between panic = unwind and abort?
- How do you convert between error types with From?
- What crates help with ergonomic error handling?
MCQ Practice
1. Which is best for a recoverable error like a missing file?
Recoverable errors should be returned as Result so the caller can handle them.
2. What does the ? operator do on an Err value?
? returns the Err early from the enclosing function, propagating the error.
3. By default, what does panic! do to the stack?
The default panic behavior unwinds the stack, running destructors, then terminates the thread.
Flash Cards
When to use panic!? — For unrecoverable bugs and broken invariants where continuing makes no sense.
When to return Result? — For expected, recoverable failures the caller should handle.
What does ? do? — Propagates an Err early out of the current function, or unwraps Ok.
Default panic behavior? — Unwinds the stack running destructors, then terminates the thread.
panic = 'abort' effect? — Skips unwinding and exits immediately, producing a smaller binary.