I have the following code:
use std::thread;
use std::panic;
pub fn main(){
thread::spawn(move || {
panic::catch_unwind(|| {
// panic!("Oh no! A horrible error.");
let s: Option<u32> = None;
s.expect("Nothing was there!");
})
})
.join()
.and_then(|result| {
match result {
Ok(ref val) => {
println!("No problems. Result was: {:?}", val);
}
Err(ref err) => {
if let Some(err) = err.downcast_ref::<&'static str>() {
println!("Error: {}", err);
} else {
println!("Unknown error type: {:?}", err);
}
}
}
result
});
}
When I trigger a panic!
directly (by uncommenting the line in the code above), then I get an output which includes my error message:
Error: Oh no! A horrible error.
But, if I use Option::expect(&str)
, as above, then the message cannot be downcast to &'static str
, so I can't get the error message out:
Unknown error type: Any
How can I get the error message, and how would I find the correct type to downcast to in the general case?
Option::expect
expects a message as a &str
, i.e. a string slice with any lifetime. You can't coerce a &str
to a &'static str
, as the string slice may refer to the interior of a String
or Box<str>
that could be freed at any time. If you were to keep a copy of the &'static str
around, you would be able to use it after the String
or Box<str>
has been dropped, and that would be undefined behavior.
An importail detail is that the Any
trait cannot hold any lifetime information (hence the 'static
bound), as lifetimes in Rust are erased at compile time. Lifetimes are used by the compiler to validate your program, but a program cannot distinguish a &'a str
from a &'b str
from a &'static str
at runtime.
[...] how would I find the correct type to downcast to in the general case?
Unfortunately, it's not easy. Any
has a method (unstable as of Rust 1.15.1) named get_type_id
that lets you obtain the TypeId
of the concrete object referred to by the Any
. That still doesn't tell you explicitly what type that is, as you still have to figure out which type this TypeId
belongs to. You would have to get the TypeId
of many types (using TypeId::of
) and see if it matches the one you got from the Any
, but you could do the same with downcast_ref
.
In this instance, it turns out that the Any
is a String
. Perhaps Option::expect
could eventually be specialized such that it panics with the string slice if its lifetime is 'static
and only allocates a String
if it's not 'static
.
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