从io :: Result()获取堆栈跟踪?

在rust中,如果有一棵深层的函数树都调用io :: Result类型的所有调用IO操作,并使用问号运算符进行错误处理,那么如何获取堆栈跟踪以查看哪个IO操作失败?

例如:

fn func2(param: u32) -> io::Result<u32> {
    perform_io1(param)?;
    perform_io2(param + 10)   
}

fn func1(param: String) -> io::Result<u32> {
    let v = perform_io3(param)?;
    perform_io4(v)?;
    let v2 = func2(v * 3)?;
    perform_io5()
}

fn main() {
    func1("test".to_string()).
        expect("func1 failed");
}

运行时,如果func1()或func2()中的IO操作之一失败,则会出现类似以下错误:

thread 'main' panicked at 'func1 failed: Os { code: 16,kind: Other,message: "Device or resource busy" }',src/libcore/result.rs:1084:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace.

如果使用“ RUST_BACKTRACE = 1”执行,则回溯并没有太大帮助:

   <snip>
   8: rust_begin_unwind
             at src/libstd/panicking.rs:311
   9: core::panicking::panic_fmt
             at src/libcore/panicking.rs:85
  10: core::result::unwrap_failed
             at src/libcore/result.rs:1084
  11: core::result::Result<T,E>::expect
             at /rustc/625451e376bb2e5283fc4741caa0a3e8a2ca4d54/src/libcore/result.rs:879
  12: example::main
             at src/main.rs:14
  13: std::rt::lang_start::{{closure}}
             at /rustc/625451e376bb2e5283fc4741caa0a3e8a2ca4d54/src/libstd/rt.rs:64
  14: std::rt::lang_start_internal::{{closure}}
             at src/libstd/rt.rs:49
  <snip>

问题是它不会告诉您哪个io操作导致了失败。任何设备操作都可能导致“设备或资源繁忙”。

很棒的事情是得到这样的东西:

    thread 'main' panicked at 'func1 failed: Os { code: 16,- src/libcore/result.rs:1084:5
    - src/main.rs:3 - perform_io2(param + 10)
    - src/main.rs:9 - func2(v * 3)
    - src/main.rs:14 - func1("test".to_string())

当然,这意味着?操作员需要将故障封装到每个传递的io:Err中,直到传递给Expect()。

在Rust中实现这一目标的最干净的方法是什么?理想情况下,不必为每个io操作的结果添加匹配表达式即可记录结果并将其传递回去。或者只是使用unwrap()而不是? (这将防止在main()中更优雅地处理该错误)。

a405387759 回答:从io :: Result()获取堆栈跟踪?

当然,在搜索了一段时间并最终提出问题之后,我在30分钟后找到了解决方案:

输入error_chain条板箱:

因此生成的代码必须类似于:

#![recursion_limit = "1024"]

#[macro_use]
extern crate error_chain;

mod errors {
    error_chain!{}
}

use errors::*;

fn func2(param: u32) -> Result<u32> {
    perform_io1(param).chain_err(|| "failed to perform io1")?;
    perform_io2(param + 10).chain_err(|| "failed  to perform io2")
}

fn func1(param: String) -> Result<u32> {
    let v = perform_io3(param).chain_err(|| "failed to perform io3")?;
    perform_io4(v).chain_err(|| "failed to perform io4")?;
    let v2 = func2(v * 3).chain_err(|| "func2 failed")?;
    perform_io5().chain_err(|| "failed to perform io5")
}

fn main() {
    if let Err(ref e) = run() {
        use std::io::Write;
        let stderr = &mut ::std::io::stderr();
        let errmsg = "Error writing to stderr";

        writeln!(stderr,"error: {}",e).expect(errmsg);

        for e in e.iter().skip(1) {
            writeln!(stderr,"caused by: {}",e).expect(errmsg);
        }

        if let Some(backtrace) = e.backtrace() {
            writeln!(stderr,"backtrace: {:?}",backtrace).expect(errmsg);
        }

        ::std::process::exit(1);
    }
}

fn run() -> Result<()> {
    use std::fs::File;

    // This operation will fail
    func1("test".to_string()).
        .chain_err(|| "func1 failed")?;

    Ok(())
}

基于:the template recommended by Brian Anderson

当然,在实际示例中,错误消息应该看起来更好。

本文链接:https://www.f2er.com/3167648.html

大家都在问