当使用 catch_unwind 处理恐慌时,为什么不能将 Option.expect() 消息向下转换为 &'static str ?

Pet*_*all 6 error-handling downcast rust

我有以下代码:

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
    });
}
Run Code Online (Sandbox Code Playgroud)

当我panic!直接触发 a 时(通过取消注释上面代码中的行),然后我得到一个包含我的错误消息的输出:

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
    });
}
Run Code Online (Sandbox Code Playgroud)

但是,如果我使用Option::expect(&str),如上所述,则消息无法向下转换为&'static str,因此我无法获取错误消息:

Error: Oh no! A horrible error.
Run Code Online (Sandbox Code Playgroud)

我如何获得错误消息,以及在一般情况下如何找到向下转换的正确类型?

Fra*_*gné 2

Option::expect期望消息为 a &str,即具有任意生命周期的字符串切片。您不能将 a 强制转换&str为 a &\'static str,因为字符串切片可能引用 a 的内部StringBox<str>可以随时释放。如果您要保留 around 的副本&\'static str,则可以在删除Stringor后使用它Box<str>,这将是未定义的行为。

\n\n

一个重要的细节是该Any特征不能保存任何生命周期信息(因此是\'static界限),因为 Rust 中的生命周期在编译时被删除。编译器使用生命周期来验证程序,但程序无法在运行时区分 a&\'a str&\'b stra &\'static str

\n\n
\n

[...]\xc2\xa0在一般情况下我如何找到正确的类型来向下转换?

\n
\n\n

不幸的是,这并不容易。Any有一个名为 的方法(从 Rust 1.15.1 开始不稳定)get_type_id,可以让您获取TypeId所引用的具体对象的Any。这仍然没有明确告诉您它是什么类型,因为您仍然必须弄清楚它TypeId属于哪种类型。您必须获得TypeId多种类型的TypeId::of,并查看它是否与您从 获得的类型匹配Any,但您可以使用 执行相同的操作downcast_ref

\n\n

在本例中,事实证明Any是一个String. 也许Option::expect最终会被专门化,如果它的生命周期是,它会因字符串切片而恐慌,并且只有在不是时才\'static分配 aString\'static

\n