如何在异步代码中使用 panic::catch_unwind?

Osk*_*son 3 rust async-await

使用同步代码时,我可以这样使用panic::catch_unwind

#[actix_rt::test]
async fn test_sync() -> Result<(), Error> {
    println!("before catch_unwind");
    let sync_result = panic::catch_unwind(|| {
        println!("inside sync catch_unwind");
        panic!("this is error")
    });
    println!("after catch_unwind");

    assert!(sync_result.is_ok());

    Ok(())
}
Run Code Online (Sandbox Code Playgroud)

使用在catch_unwind块内执行的异步代码时,我如何做同样的事情?我无法弄清楚如何运行块,同时还能够在块之后运行一些代码并最终断言结果。

这是我到目前为止:

#[actix_rt::test]
async fn test_async() -> Result<(), Error> {
    println!("before catch_unwind");
    let async_result = panic::catch_unwind(|| async {
        println!("inside async catch_unwind");
        panic!("this is error")
    }).await;
    println!("after catch_unwind");

    assert!(async_result.is_ok());

    Ok(())
}
Run Code Online (Sandbox Code Playgroud)

She*_*ter 6

不会尝试直接使用它们。相反,使用FutureExt::catch_unwindStreamExt::catch_unwind

use futures::FutureExt; // 0.3.5

#[tokio::test]
async fn test_async() -> Result<(), Box<dyn std::error::Error>> {
    println!("before catch_unwind");

    let may_panic = async {
        println!("inside async catch_unwind");
        panic!("this is error")
    };

    let async_result = may_panic.catch_unwind().await;

    println!("after catch_unwind");

    assert!(async_result.is_ok());

    Ok(())
}
Run Code Online (Sandbox Code Playgroud)

  • 谢谢,这很好用!但是,对于更复杂的示例,在调用 sqlx 等库中的异步函数时,我确实会遇到“可能无法安全地跨展开边界传输”之类的错误:/ (3认同)
  • 这在 may_panic 时有效,如示例所示,是在此模块中创建的 future。但是,如果 may_panic 中的代码等待由另一个方法返回的另一个 future(其中 futures:FutureExt 未纳入范围),则它不起作用。在这种情况下,catch_unwind 会抱怨 future 不可跨展开边界传输,因为 async 函数本身返回的 future 会等待另一个不可传输的 future。有什么想法可以解决这个问题吗? (3认同)