rust - AssertUnwindSafe 如何与 CatchUnwind future 一起使用

标签 rust async-await 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);
    }
}
但是,我一直无法弄清楚如何使用 future 和异步/等待来做到这一点。在这种情况下,我会尝试调用已声明为异步的函数。我尝试了各种类似下面的代码:
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包装与否,因为您在调用它之前要打开它。所以,你应该断言 future 本身是安全的:

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);
}

关于rust - AssertUnwindSafe 如何与 CatchUnwind future 一起使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65762689/

相关文章:

rust - 预期类型与收到的类型不匹配

rust - 如何使用 dbus 在 Rust 中检测应用程序的唯一性

reference - 我什么时候不应该为引用该特征的实现者而实现该特征?

rust - 有没有办法在非夜间 Rust 上查看扩展的宏?

json - 东京和塞尔德 : deserializing JSON

java - 即使 Future.get() 从未被调用,是否会在方法执行结束时等待 Future API 调用?

python - 如何使用tornado gen.Task/gen.coroutine装饰器实现并行性

没有等待或返回的 C# 异步任务方法

c# - 用于测试调用异步方法的 ICommand 的模式

带有过滤器的Scala Future以进行理解