capypad
0 day streak
rust / intermediate
Snippet

Panic Recovery with catch_unwind

The catch_unwind function enables recovery from panics, wrapping closure execution and returning Results where Ok contains the normal result or Err contains the panic payload. AssertUnwindSafe is a marker trait indicating the closure doesn't contain resources requiring deterministic cleanup through Drop. When a panic occurs, Rust will still run destructors for Drop types during unwinding, but catch_unwind prevents the panic from propagating to the calling thread. This is valuable for隔离 dangerous code in tests or server request handling.

snippet.rs
rust
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
use std::panic::{catch_unwind, AssertUnwindSafe};
 
fn risky_operation(input: i32) -> Result<i32, String> {
if input < 0 {
panic!("Negative input not allowed: {}", input);
}
Ok(input * 2)
}
 
fn safe_wrapper() {
let result = catch_unwind(AssertUnwindSafe(|| {
risky_operation(-5)
}));
 
match result {
Ok(Ok(value)) => println!("Success: {}", value),
Ok(Err(msg)) => println!("Logic error: {}", msg),
Err(_) => println!("Panic was caught!"),
}
}
 
struct Resource {
data: String,
}
 
impl Drop for Resource {
fn drop(&mut self) {
println!("Cleaning up: {}", self.data);
}
}
 
fn with_cleanup() {
let result = catch_unwind(AssertUnwindSafe(|| {
let resource = Resource { data: String::from("allocated") };
panic!("Simulated failure");
}));
if result.is_err() {
println!("Panic caught, destructor still ran");
}
}
 
fn main() {
safe_wrapper();
with_cleanup();
}
Breakdown
1
catch_unwind(AssertUnwindSafe(||
Wrapper for recoverable panic detection
2
Ok(Ok(value))
Triple nested: no panic, no error, contains value
3
Err(_) => println!("Panic was caught!")
Panic payload caught, thread continues
4
struct Resource impl Drop
Destructor guarantee even during panic unwinding
5
result.is_err()
Check if panic occurred without reading payload