错误处理 – 当使用catch_unwind处理恐慌时,为什么Option.expect()消息不能作为&’静态str转发?

我有以下代码:

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
    });
}

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

Error: Oh no! A horrible error.

但是,如果我使用Option :: expect(& str),如上所述,那么消息不能向下转换为&’static str,所以我无法得到错误消息:

Unknown error type: Any

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

最佳答案
Option::expect期望消息为& str,即具有任何生命周期的字符串切片.你不能将& str强制转换为&’静态str,因为字符串切片可以引用String或Box< str>的内部.可以在任何时候释放.如果你要保留&’静态str的副本,你就可以在String或Box< str>之后使用它.已被删除,这将是未定义的行为.

一个重要的细节是Any trait不能保存任何生命周期信息(因此是’静态绑定),因为Rust的生命周期在编译时被删除.编译器使用生命周期来验证您的程序,但程序无法在运行时将&’str和&’b str与&’静态str区分开来.

[…] how would I find the correct type to downcast to in the general case?

不幸的是,这并不容易.任何一个名为get_type_id的方法(不稳定的Rust 1.15.1)都可以让你获得Any引用的具体对象的TypeId.这仍然没有明确告诉你什么类型,因为你仍然需要弄清楚这个TypeId属于哪种类型.你必须获得许多类型的TypeId(使用TypeId::of)并查看它是否与你从Any获得的类型匹配,但你可以使用downcast_ref.

在这个例子中,事实证明Any是一个字符串.也许Option :: expect最终可能是专用的,如果它的生命周期是’静态的话它会对字符串切片感到恐慌,如果它不是’静态的话只分配一个字符串.

点赞