std::result::结果恐慌要记录

use*_*932 4 rust

我在单独的线程中运行一些代码:

    fn f1() -> Result<(), String> { Err("err1".to_string()) }
    fn f2() -> Result<(), String> { Err("err2".to_string()) }
    ::std::thread::spawn(move || {
      f1().expect("f1 failed");
      f2().expect("f2 failed");
    });
Run Code Online (Sandbox Code Playgroud)

我也用日志箱进行日志记录。

结果我想要panic!打电话error!而不是print!

我找到了恐慌钩子,但我不喜欢unwrap这样的代码:

panic::set_hook(Box::new(|panic_info| {
    error!("panic occured: {:?}", panic_info.payload().downcast_ref::<&str>().unwrap());
}));
Run Code Online (Sandbox Code Playgroud)

我担心:

这通常(但并非总是)是&'static strString

但不会downcast总是成功吗?

Mat*_* M. 5

这通常(但并非总是)是&'static strString

这意味着开发人员(您使用的库的开发人员)可能会使用另一种类型。在这种情况下,调用downcast_ref将会失败。

我的建议是处理您了解的情况并添加带有默认消息的包罗万象的情况。

此外,您还应该考虑打印位置,因为即使没有消息,它也非常有用。

总而言之:

use std::panic;
use std::ops::Deref;

panic::set_hook(Box::new(|panic_info| {
    let (filename, line) =
        panic_info.location().map(|loc| (loc.file(), loc.line()))
            .unwrap_or(("<unknown>", 0));

    let cause = panic_info.payload().downcast_ref::<String>().map(String::deref);

    let cause = cause.unwrap_or_else(||
        panic_info.payload().downcast_ref::<&str>().map(|s| *s)
            .unwrap_or("<cause unknown>")
    );

    error!("A panic occurred at {}:{}: {}", filename, line, cause);
}));
Run Code Online (Sandbox Code Playgroud)

让我们打开它:

  • 首先,我们从该位置获取文件名和行,并提供默认值以防它们未知,
  • 然后我们检查是否payload是 a String,如果是则取消引用它,
  • 然后,如果不是,我们检查它是否是 a &str,如果不是则提供默认值,
  • 最后,我们打印所有积累的信息。