在IT技术中,一种常见的技巧是使用返回Result<X, Box<dyn Error>>
来注释函数,以便允许它们返回任何错误。然而,如果没有实现Send
,则无法从线程返回此类型的错误本身。例如,下面的代码:
use rayon::prelude::*; // 1.5.1
use std::error::Error;
fn main(){
["1", "2", "three"]
.into_par_iter()
.try_for_each(|i| -> Result<usize, Box<dyn Error>> {
let inner = i.parse::<usize>()?;
Ok(inner)
}
);
}
给出以下错误:
error[E0277]: `dyn std::error::Error` cannot be sent between threads safely
(编程示例)
另一方面,如果您尝试指定错误必须实现Send
,那么?
操作符将不再起作用:
use rayon::prelude::*; // 1.5.1
use std::error::Error;
fn main(){
["1", "2", "three"]
.into_par_iter()
.try_for_each(|i| -> Result<usize, Box<dyn Error + Send>> {
let inner = i.parse::<usize>()?;
Ok(inner)
}
);
}
error[E0277]: `?` couldn't convert the error to `Box<dyn std::error::Error + Send>`
我如何继续使用 Box<dyn Error>
的快捷方式,但仅针对可以发送的错误,使其跨线程工作?(playground)
thiserror
装箱是我个人最喜欢的方法,可以减少样板代码,但还有其他几种替代方案。 - Thomasanyhow
创建。但这是处理动态错误的“内置”方式。它解决的问题是有一个可能引发多种不同错误类型的闭包,而我不能打扰使用自己的错误类型来统一它们。 - Migwellanyhow
crate 满足,其 titular 类型基本上是对Box<dyn Error + Send + Sync + 'static>
的包装,其流行程度表明存在充分的需求。(它的作者 David Tolnay 还写了thiserror
和serde
等等。)与 C++ 异常不同,传播是显式的,涉及返回Result
,通常使用?
运算符,因此没有什么事情会在背后发生。 - user4815162342