我正在实现一个 C 库的包装器,它接受回调,并且回调将在 Rust 中实现。鉴于panicking in Rust when calling from C is undefined behavior ,我想在任何潜在的 Rust panic 进入 C 之前捕获它们。
我一直在阅读有关 std::panic::catch_unwind
的内容。包装器对性能敏感,我宁愿避免使用类似 Mutex
的类型。我想将我的结果保存在 Option<i32>
中并将其设置为 Some(value)
在没有 panic 的情况下。 None
将表明该函数未成功执行,因此一定发生了 panic 。
是Option<i32>
放松安全吗?如果不是,什么情况下会出现问题?我可以把它包在 std::panic::AssertUnwindSafe
里吗?
这是我使用 AssertUnwindSafe
的示例包裹整个封闭物。
use std::panic::{self, AssertUnwindSafe};
fn random_function_that_might_panic(a: i32) -> i32 {
if a == 42 {
panic!("did you forget a towel?");
}
a * 2
}
fn do_not_panic(a: i32) {
let mut result = None;
let unwind_state = panic::catch_unwind(AssertUnwindSafe(|| {
result = Some(random_function_that_might_panic(a)); // get result, but this could panic
}));
match unwind_state {
Ok(()) => {
match result {
Some(value) => {
println!("Result: {:?}", value);
}
None => {
// this should never happen...
println!("No result but no panic?");
}
}
}
Err(e) => {
println!("caught panic: {:?}", e);
}
}
}
fn main() {
do_not_panic(1);
do_not_panic(2);
do_not_panic(3);
do_not_panic(42);
}
(请参阅上面的 playground 。)
我不知道如何包装 Option<i32>
在AssertUnwindSafe
,所以我在这里包裹了整个封闭物。我该如何包装 Option<i32>
?
最佳答案
Is
Option<i32>
unwind safe?
是的。当你可以问编译器时,就没有理由问人类这个问题:
fn implements<T: std::panic::UnwindSafe>() {}
fn main() {
implements::<Option<i32>>();
}
您的真正问题应该是:
Is
&mut Option<i32>
unwind safe?
事实并非如此,但您可能已经知道了。我猜你在添加 AssertUnwindSafe
之前遇到了这个编译器错误这告诉你它不安全:
error[E0277]: the trait bound `&mut std::option::Option<i32>: std::panic::UnwindSafe` is not satisfied in `[closure@src/main.rs:12:44: 14:6 result:&mut std::option::Option<i32>, a:&i32]`
--> src/main.rs:12:24
|
12 | let unwind_state = panic::catch_unwind(|| {
| ^^^^^^^^^^^^^^^^^^^ the type &mut std::option::Option<i32> may not be safely transferred across an unwind boundary
|
= help: within `[closure@src/main.rs:12:44: 14:6 result:&mut std::option::Option<i32>, a:&i32]`, the trait `std::panic::UnwindSafe` is not implemented for `&mut std::option::Option<i32>`
= note: required because it appears within the type `[closure@src/main.rs:12:44: 14:6 result:&mut std::option::Option<i32>, a:&i32]`
= note: required by `std::panic::catch_unwind`
我会这样编写你的代码,因为它的值(value)是:
fn do_not_panic(a: i32) {
let result = panic::catch_unwind(|| random_function_that_might_panic(a)).ok();
match result {
Some(value) => {
println!("Result: {:?}", value);
}
None => {
println!("caught panic");
}
}
}
没有可变变量,没有额外的嵌套,没有“这永远不应该发生”的评论。
另请参阅:
关于rust - Option<i32> 展开安全吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52300517/