AssertUnwindSafe 如何与 CatchUnwind 未来一起使用
How can AssertUnwindSafe be used with the CatchUnwind future
我希望能够将可变引用传递给函数,但要捕获可能来自该函数的展开。目的是用于编写一些测试包装器(设置、拆卸),而不是一般的错误处理。
如果我使用的是典型的同步代码,我可以编译并运行它...
struct MyStruct {
n: u32
}
fn my_func(s: &mut MyStruct) {
s.n += 1;
panic!("Oh no!");
}
fn main() {
let mut ctx = MyStruct { n: 1 };
let mut wrapper = std::panic::AssertUnwindSafe(&mut ctx);
let result = std::panic::catch_unwind(move || {
my_func(*wrapper);
});
// Do some cleanup of `ctx` here.
if let Err(err) = result {
std::panic::resume_unwind(err);
}
}
但是,我一直无法弄清楚如何使用期货和 async/await 来做到这一点。在那种情况下,我将尝试调用一个已声明为异步的函数。我尝试了各种方法,例如下面的代码:
async fn run_async(s: &mut MyStruct) {
s.n += 1;
panic!("Oh no!");
}
#[tokio::main]
async fn main() {
let mut ctx = MyStruct { n : 1 };
let wrapper = std::panic::AssertUnwindSafe(&mut ctx);
let result = async move {
run_async(*wrapper).catch_unwind().await
}.await;
println!("{:?}", result);
}
但是,我通常会遇到如下错误:
the type &mut MyStruct
may not be safely transferred across an unwind boundary`.
我相信 AssertUnwindSafe
应该可以帮助解决这些问题,就像他们处理同步代码一样。但是在 AssertUnwindSafe 和 async/await.
的交集处显然有一些我不理解的地方
使用std::panic::catch_unwind
,提供的闭包必须是UnwindSafe
,在里面使用可变引用会使闭包无法实现UnwindSafe
.这就是包装引用并移动引用的原因。
然而,对于 futures::future::FutureExt::catch_unwind
,提供的 future 必须是 UnwindSafe
,并且 run_async
生成的 future 不关心是否引用是否来自 AssertUnwindSafe
包装器,因为您在调用它之前要打开它。所以,你应该断言未来本身是安全的:
use futures::future::FutureExt;
struct MyStruct {
n: i32
}
async fn run_async(s: &mut MyStruct) {
s.n += 1;
panic!("Oh no!");
}
#[tokio::main]
async fn main() {
let mut ctx = MyStruct { n : 1 };
let result = async move {
// AssertUnwindSafe moved to the future
std::panic::AssertUnwindSafe(run_async(&mut ctx)).catch_unwind().await
}.await;
println!("{:?}", result);
}
我希望能够将可变引用传递给函数,但要捕获可能来自该函数的展开。目的是用于编写一些测试包装器(设置、拆卸),而不是一般的错误处理。
如果我使用的是典型的同步代码,我可以编译并运行它...
struct MyStruct {
n: u32
}
fn my_func(s: &mut MyStruct) {
s.n += 1;
panic!("Oh no!");
}
fn main() {
let mut ctx = MyStruct { n: 1 };
let mut wrapper = std::panic::AssertUnwindSafe(&mut ctx);
let result = std::panic::catch_unwind(move || {
my_func(*wrapper);
});
// Do some cleanup of `ctx` here.
if let Err(err) = result {
std::panic::resume_unwind(err);
}
}
但是,我一直无法弄清楚如何使用期货和 async/await 来做到这一点。在那种情况下,我将尝试调用一个已声明为异步的函数。我尝试了各种方法,例如下面的代码:
async fn run_async(s: &mut MyStruct) {
s.n += 1;
panic!("Oh no!");
}
#[tokio::main]
async fn main() {
let mut ctx = MyStruct { n : 1 };
let wrapper = std::panic::AssertUnwindSafe(&mut ctx);
let result = async move {
run_async(*wrapper).catch_unwind().await
}.await;
println!("{:?}", result);
}
但是,我通常会遇到如下错误:
the type
&mut MyStruct
may not be safely transferred across an unwind boundary`.
我相信 AssertUnwindSafe
应该可以帮助解决这些问题,就像他们处理同步代码一样。但是在 AssertUnwindSafe 和 async/await.
使用std::panic::catch_unwind
,提供的闭包必须是UnwindSafe
,在里面使用可变引用会使闭包无法实现UnwindSafe
.这就是包装引用并移动引用的原因。
然而,对于 futures::future::FutureExt::catch_unwind
,提供的 future 必须是 UnwindSafe
,并且 run_async
生成的 future 不关心是否引用是否来自 AssertUnwindSafe
包装器,因为您在调用它之前要打开它。所以,你应该断言未来本身是安全的:
use futures::future::FutureExt;
struct MyStruct {
n: i32
}
async fn run_async(s: &mut MyStruct) {
s.n += 1;
panic!("Oh no!");
}
#[tokio::main]
async fn main() {
let mut ctx = MyStruct { n : 1 };
let result = async move {
// AssertUnwindSafe moved to the future
std::panic::AssertUnwindSafe(run_async(&mut ctx)).catch_unwind().await
}.await;
println!("{:?}", result);
}