在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()中更优雅地处理该错误)。