如果使用set_hook,我们可以获得大量信息,尤其是堆栈跟踪 - 这非常有帮助。然而,对于catch_unwind,我只得到 a Result,其中几乎不包含任何有用的信息。因此,我想知道如何使用 Rust 获取恐慌信息(尤其是堆栈跟踪)catch_unwind?
我处于多线程环境中,其中有许多线程同时运行,任何线程都可能出现恐慌。我想我应该set_hook与 一起使用catch_unwind,并且还使用一些线程局部变量,但我不确定它是否可行以及细节。
有什么办法可以做到这一点吗?在终端图形库中,如果发生异常,异常将在显示之前被刷新,这使得使用该库进行编程非常困难。
impl Drop for Terminal {
fn drop(&mut self) {
self.outbuffer.write_all(&self.driver.get(DevFn::ShowCursor)).unwrap();
self.outbuffer.write_all(&self.driver.get(DevFn::Reset)).unwrap();
self.outbuffer.write_all(&self.driver.get(DevFn::Clear)).unwrap();
self.outbuffer.write_all(&self.driver.get(DevFn::ExitCa)).unwrap();
self.flush().unwrap(); // If an exception occurs, this will reclear the screen and remove the output
self.termctl.reset().unwrap();
SIGWINCH_STATUS.store(false, Ordering::SeqCst);
RUSTTY_STATUS.store(false, Ordering::SeqCst);
}
}
Run Code Online (Sandbox Code Playgroud)
如果我要注释掉self.flush().unwrap();异常,则会打印异常,但是即使程序结束后,终端也不会正确刷新屏幕并在终端上留下图形。
是否可以在程序开始时指定用于写入的自定义缓冲区恐慌?或者可能写一个黑客技巧来做到这一点?这样,在刷新之后,我们可以检查该缓冲区内是否有任何内容,如果有,我们就知道发生了异常并可以将其打印出来。
然而,通过注释掉self.flush().unwrap();,我们看到了实际的异常,但现在是一个非常丑陋的终端。该解决方案将不起作用,因为正确执行的程序仍然需要刷新,因为不需要显示错误
在我的overflower_support箱子的测试中,我发现我收到很多关于已经使用的恐慌的虚假报告std::panic::catch_unwind(_).这有点不幸,因为它掩盖了可能发生的真实错误.消息看起来像:
thread 'safe' panicked at 'arithmetic overflow', src/lib.rs:56
Run Code Online (Sandbox Code Playgroud)
为了平息那些dont_panic(..)令人分心的消息,我引入了函数,它劫持了恐慌处理程序,调用了一个闭包并在完成时重置了恐慌处理程序,返回了闭包结果.它看起来像这样:
fn dont_panic<F, A, R>(args: A, f: F) -> R
where F: Fn(A) -> R
{
let p = panic::take_hook();
panic::set_hook(Box::new(|_| ()));
let result = f(args);
panic::set_hook(p);
result
}
Run Code Online (Sandbox Code Playgroud)
但是,在函数中使用此函数来进行检查有点令人惊讶,不仅可以消除所需的消息,还可以快速检查错误输出,这对我来说显然很有价值.即使将测试限制在一个线程中也会发生这种情
#[test]
fn test_some_panic() {
fn check(x: usize) -> bool {
let expected = if x < 256 { Some(x) } else { None };
let actual = dont_panic(|| panic::catch_unwind(|| { assert!(x < 256); x }).ok());
expected …Run Code Online (Sandbox Code Playgroud) 我遇到了以下两种方式:
#[derive(Debug)]
struct InputList(i32, i32, i32, i32);
#[derive(Debug)]
struct OutputList(i32, i32, i32, i32);
// Option 1
fn foo(input_list: InputList) -> OutputList {
return OutputList(input_list.0, input_list.1, input_list.2, input_list.3);
}
// Option 2
fn bar(input_list: InputList) -> OutputList {
OutputList(input_list.0, input_list.1, input_list.2, input_list.3)
}
fn main() {
let input_list1 = InputList(1, 2, 3, 4);
let input_list2 = InputList(6, 7, 8, 9);
println!("foo() invocation output: {:?}", foo(input_list1));
println!("bar() invocation output: {:?}", bar(input_list2));
}
Run Code Online (Sandbox Code Playgroud)
只有这两种选择吗?