Rust 无法跨等待点发送未包装的结果数据

Rust cannot send unwrapped Result data across await point

考虑以下代码:

use std::error::Error;

use tokio::sync::mpsc;

fn gen_data() -> Result<i32, Box<dyn Error>> {
    Ok(42)
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let (tx, rx) = mpsc::channel(10);

    // TODO: future cannot be sent between threads safely the trait `Send` is not implemented for `dyn std::error::Error`
    tokio::spawn(async move {
        if let Ok(data) = gen_data() {
            tx.send(data).await;
        }
    });

    while let Some(res) = rx.recv().await {
        println!("{}", res);
    }

    Ok(())
}

我大致了解错误的意思。是不是说我的 gen_data 函数的 Err 结果在我 awaiting 之前没有被删除?

我不需要函数中的错误数据。我试图实现的逻辑是,如果 gen_data 返回错误,则不执行任何操作,如果 gen_data 有效,则发送它。

如何重构代码以使其能够编译?

在 real-world 应用程序中,您可能应该避免使用 Box<dyn Error>,而是创建一个自定义错误枚举,它可以表示您的应用程序可能发生的每个错误。例如,参见 this post 解释如何实现这一点。因此,如果您正在考虑重构代码,现在可能是改变错误处理方式的最佳时机。

但是,如果您想将错误保留为特征对象,只需将 Box<dyn Error> 更改为 Box<dyn Error + Send> 即可将它们强制为 Send。同样,如果您需要它们也是 Sync,请使用 Box<dyn Error + Send + Sync>。这种方法的唯一问题是这个约束将传播到你的代码的其余部分:如果某个时刻一个函数只有 return 一个 Box<dyn Error>,那么你不能得到一个 Box<dyn Error + Send>回来,所以即使是常规(非async)函数也必须return错误也是Send,这有点奇怪。