Avoiding Unnecessary Panics
Production Rust code treats panics (unwrap(), expect(), out-of-bounds v[i], unchecked a / b, and mid-character &s[a..b]) as bugs or unrecoverable invariant violations—never as normal control flow for handling bad user input, network failures, or edge-case data.
Non-Panicking Replacements for Common Panicking Operations
| Panicking Operation | Non-Panicking Replacement | Return Type |
|---|---|---|
opt.unwrap() / res.unwrap() |
opt? / res?, if let, let ... else, or .unwrap_or_default() |
Propagates or handles None / Err |
slice[i] / vec[i] |
slice.get(i) / slice.get_mut(i) |
Option<&T> / Option<&mut T> |
slice[0] / slice[slice.len() - 1] |
slice.first() / slice.last() |
Option<&T> |
&s[start..end] (string slice) |
s.get(start..end) or s.split_at_checked(mid) |
Option<&str> / Option<(&str, &str)> |
vec.remove(i) / vec.split_off(i) |
Check i < vec.len() or use vec.pop() |
Option<T> |
a + b, a - b, a * b (integer overflow) |
a.checked_add(b), a.saturating_sub(b) |
Option<T> or clamped T |
a / b (division by zero or MIN / -1) |
a.checked_div(b) |
Option<T> |
Early Return Guards with let ... else
When a function cannot use ? (for example, when it returns () or needs to log a warning and continue in a loop), the let Pattern = expr else { diverge } statement unwraps Some(v) or Ok(v) into the outer scope without indenting the rest of the function or calling .unwrap():
fn process_metric_lines(lines: &[&str]) -> Vec<(&str, u64)> {
let mut valid = Vec::new();
for &line in lines {
// Unwraps `Some((name, raw_val))` or skips malformed lines cleanly:
let Some((name, raw_val)) = line.split_once(':') else {
continue;
};
// Unwraps `Ok(value)` or skips unparseable numbers cleanly:
let Ok(value) = raw_val.trim().parse::<u64>() else {
continue;
};
valid.push((name.trim(), value));
}
valid
}
fn main() {
let input = [
"cpu_load: 72",
"malformed_line_without_colon",
"mem_mb: not_a_number",
"disk_gb: 512",
];
println!("Valid metrics: {:?}", process_metric_lines(&input));
}
Valid metrics: [("cpu_load", 72), ("disk_gb", 512)]
Enforcing Panic-Free Code with Clippy Lints
In libraries or high-reliability services, enable Clippy's restriction lints to reject .unwrap(), .expect(), and direct indexing at compile time:
#![deny(clippy::unwrap_used)]
#![deny(clippy::expect_used)]
#![deny(clippy::indexing_slicing)]
When an invariant truly is guaranteed by surrounding logic (such as a hardcoded valid regex or a just-checked condition), prefer .expect("reason why this invariant holds") over bare .unwrap(), phrasing the message as an assertion explanation rather than a generic error message.