I know that in Rust there is no try/catch, and you can't throw a rolling save from the thread that is currently panicking.
I know you should not create and handle errors like this. This is just for example's sake.
However, I am wondering what the best way to recover from a panic is. This is what I have now:
use std::thread; fn main() { println!("Hello, world!"); let h = thread::spawn(|| { thread::sleep_ms(1000); panic!("boom"); }); let r = h.join(); match r { Ok(r) => println!("All is well! {:?}", r), Err(e) => println!("Got an error! {:?}", e) } println!("Exiting main!"); }
Is there a better way to handle errors from other threads? Is there a way to capture the message of the panic? This seems to only tell me that the error is of type Any
. Thanks!
Keep in mind that "recover" is perhaps not the best way of phrasing this in Rust. You don't really recover from panics in Rust, you isolate them, then detect them. There is no On Error Resume Next :P.
Recover is a function provided by Go which takes control of a panicking goroutine. recover() can only be used inside deferred functions. If you call recover() during normal flow, it will simply return nil . However, if a goroutine is panicking, recover() will capture the panic value.
You can override the panic hook using std::panic::set_hook() . Inside the hook a panic can be accessed as a &dyn Any + Send , which contains either a &str or String for regular panic!() invocations. To panic with a value of another other type, panic_any can be used.
Putting aside "you should be using Result
where possible," yes, this is basically how you catch a panic in Rust. Keep in mind that "recover" is perhaps not the best way of phrasing this in Rust. You don't really recover from panics in Rust, you isolate them, then detect them. There is no On Error Resume Next
:P.
That said, there are two things to add to your example. First is how to get at the panic message. The key observation is that Any
, in order to be used, must be explicitly downcast to the exact, concrete type it contains. In this case, since the panic message is a &'static str
, you need to downcast to that.
The second thing is that there is a new API in nightly called catch_panic
that lets you isolate a panic without having to start a thread. That said, it comes with the same restrictions as spawning a new thread: you cannot pass a non-'static
reference across the isolation boundary. Note that this is an unstable addition; there are no guarantees about stability yet, and you'll need a nightly compiler to access it.
Here is an example which shows both of those. You can also run this on the Rust Playpen.
#![feature(catch_panic)] use std::thread; fn main() { println!("Hello, world!"); let h = thread::spawn(|| { thread::sleep_ms(500); panic!("boom"); }); let r = h.join(); handle(r); let r = thread::catch_panic(|| { thread::sleep_ms(500); panic!(String::from("boom again!")); }); handle(r); println!("Exiting main!"); } fn handle(r: thread::Result<()>) { match r { Ok(r) => println!("All is well! {:?}", r), Err(e) => { if let Some(e) = e.downcast_ref::<&'static str>() { println!("Got an error: {}", e); } else { println!("Got an unknown error: {:?}", e); } } } }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With