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
,这有点奇怪。
考虑以下代码:
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
,这有点奇怪。