【问题标题】:How can AssertUnwindSafe be used with the CatchUnwind futureAssertUnwindSafe 如何与 CatchUnwind 未来一起使用
【发布时间】:2021-01-17 15:45:41
【问题描述】:

我希望能够将可变引用传递给函数,但捕获可能来自该函数的展开。目的是用于编写一些测试包装器(设置、拆卸),而不是一般的错误处理。

如果我使用的是典型的同步代码,我可以编译并运行它...

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

但是,我通常会遇到如下错误:

&mut MyStruct 类型可能无法安全地越过展开边界`。

我相信AssertUnwindSafe 应该可以帮助解决这些问题,就像他们处理同步代码一样。但是在 AssertUnwindSafe 和 async/await 的交叉点上,我显然有一些不明白的地方。

【问题讨论】:

    标签: rust async-await future


    【解决方案1】:

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

    【讨论】:

    • 谢谢!虽然我没有在问题中完全指定,但我也想在等待异步块后使用ctx。因此,我需要像let wrapper = &mut ctx; 这样的行在异步块之前,然后run_async(wrapper) 以确保ctx 不会移动到异步块中,而是它的可变引用。然而,理解 AssertUnwindSafe 应该是未来,而不是未来的价值,这是我所缺少的。
    猜你喜欢
    • 2019-03-17
    • 1970-01-01
    • 1970-01-01
    • 2023-03-30
    • 1970-01-01
    • 1970-01-01
    • 2013-05-30
    • 2016-12-13
    • 2017-06-17
    相关资源
    最近更新 更多