Error handling 为什么可以';t Option.expect()消息将被向下转换为&';静态str当恐慌通过catch_unwind处理时?

Error handling 为什么可以';t Option.expect()消息将被向下转换为&';静态str当恐慌通过catch_unwind处理时?,error-handling,rust,downcast,Error Handling,Rust,Downcast,我有以下代码: 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 th

我有以下代码:

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
    });
}
但是,如果我使用如上所述的
选项::expect(&str)
,则消息不能向下转换到
&'static str
,因此我无法获取错误消息:

未知错误类型:任意
如何获取错误消息,以及在一般情况下如何找到要向下转换到的正确类型?

期望消息为
&str
,即具有任何生存期的字符串片段。您不能将
&str
强制为
&str的静态str
,因为字符串片段可能指可以随时释放的
字符串或
框的内部。如果要保留
&'static str
的副本,则可以在删除
字符串
后使用它,这将是未定义的行为

一个重要的细节是,
Any
特性不能保存任何生存期信息(因此,
静态
绑定),因为Rust中的生存期在编译时被擦除。编译器使用生存期来验证程序,但程序在运行时无法区分
&'a str
&'b str
&'static str

[…]在一般情况下,我如何找到要向下转换的正确类型

不幸的是,这并不容易
Any
有一个名为的方法(从Rust 1.15.1开始不稳定),该方法允许您获得
Any
所指混凝土对象的形状。这仍然不能明确地告诉你那是什么类型,因为你仍然需要弄清楚这个
TypeId
属于哪种类型。您必须获得许多类型的
TypeId
(使用),并查看它是否与从
Any
中获得的匹配,但您可以使用
downcast\u ref
执行相同的操作


在本例中,
Any
是一个
字符串。也许
选项::expect
最终会被专门化,这样,如果字符串片的生存期是
静态的,它就会对字符串片产生恐慌,如果字符串片不是
静态的,它只分配
字符串
,,就像弗朗西斯说的,一般来说,你不能发现并转换为
恐慌的类型。然而,尽管如此,恐慌有以下规则:

  • 如果你惊慌失措使用单个参数,恐慌将具有该类型。通常这是
    &'static str
  • 如果你惊慌失措
如果有多个参数,这些参数将被视为
格式参数,用于创建
字符串
参数 这些规则记录在
panic
文档中:

考虑到这些规则,我们可以编写一个函数,在任何情况下从恐慌中提取消息,其中有一条消息可提取,这在实践中大部分时间都有效,因为大部分时间消息要么是
&'static str
要么
String

pub fn获取恐慌消息(恐慌:&Box)->选项{
恐慌
//尝试将其转换为字符串,然后将其转换为str
.downcast_ref::()
.map(字符串::as_str)
//如果失败,尝试将其转换为&'static str

。或| else(| | panic.downcast_ref::谢谢。我做了一些测试,发现即使是
panic!(my|str)
在运行时构建
my|str
时,也会被捕获为
字符串。因此
panic!()
的行为实际上正是您所描述的“也许最终”
选项的行为::expect