Error handling 从迭代器收集所有错误的惯用方法

Error handling 从迭代器收集所有错误的惯用方法,error-handling,rust,iterator,rust-result,Error Handling,Rust,Iterator,Rust Result,假设我有一些函数属性的attrs:Vec,还有一个函数fn map_属性(attr:&attribute)->结果,它将属性映射到一些代码 我知道我可以这样写: attrs.into_iter() .map(map_attribute) .collect::<Result<Vec<_>, _>()? let mut codes : Vec<TokenStream> = Vec::new(); let mut errors: Vec&

假设我有一些函数属性的
attrs:Vec
,还有一个函数
fn map_属性(attr:&attribute)->结果,它将属性映射到一些代码

我知道我可以这样写:

attrs.into_iter()
     .map(map_attribute)
     .collect::<Result<Vec<_>, _>()?
let mut codes : Vec<TokenStream> = Vec::new();
let mut errors: Vec<Error>       = Vec::new();

for attr in attrs {
    match map_attribute(attr) {
        Ok(code) => codes.push(code),
        Err(err) => errors.push(err)
    }
}

let mut error_iter = errors.into_iter();
if let Some(first) = error_iter.nth(0) {
    return Err(iter.fold(first, |mut e0, e1| { e0.combine(e1); e0 }));
}
attrs.into_iter()
.map(map\u属性)
.collect::code.push(代码),
Err(Err)=>errors.push(Err)
}
}
让mut error_iter=errors.into_iter();
如果让一些(第一)=第n个错误(0){
返回错误(iter.fold(第一个,mut e0,e1{e0.combine(e1);e0});
}

第二个版本符合我的要求,但比第一个版本要详细得多。如果可能的话,没有创建自己的迭代器,有没有更好/更惯用的方法来实现这一点?

据我所知,标准库没有一个方便的单行程序,但是优秀的
itertools
库有:

使用itertools::itertools;//0.9.0
fn main(){
让foo=vec![Ok(42),Err(“:”,Ok(321),Err(“oh-noes”);
let(代码、错误):(Vec、Vec)
=foo.into_iter().partition_map(From::From);
println!(“代码={:?}”,代码);
println!(“错误={:?}”,错误);
}

()

我最终为
迭代器编写了自己的扩展,它允许我在遇到第一个错误时停止收集代码。在我的用例中,这可能比mcarton的答案更有效,因为我只需要第一个分区存储桶(如果第二个分区存储桶为空)。此外,如果我想要,我需要折叠错误o将它们合并为一个错误

pub trait CollectToResult
{
    type Item;

    fn collect_to_result(self) -> Result<Vec<Self::Item>, Error>;
}

impl<Item, I> CollectToResult for I
where
    I : Iterator<Item = Result<Item, Error>>
{
    type Item = Item;

    fn collect_to_result(self) -> Result<Vec<Item>, Error>
    {
        self.fold(<Result<Vec<Item>, Error>>::Ok(Vec::new()), |res, code| {
            match (code, res) {
                (Ok(code), Ok(mut codes)) => { codes.push(code); Ok(codes) },
                (Ok(_), Err(errors)) => Err(errors),
                (Err(err), Ok(_)) => Err(err),
                (Err(err), Err(mut errors)) => { errors.combine(err); Err(errors) }
            }
        })
    }
}
pub trait collectoresult
{
类型项目;
fn收集结果到结果(自我)->结果;
}
impl CollectoResult for I
哪里
I:迭代器
{
类型项目=项目;
fn收集到结果(自)->结果
{
self.fold(::Ok(Vec::new()),| res,code |{
匹配(代码,res){
(Ok(代码),Ok(mut代码))=>{code.push(代码);Ok(代码)},
(正常(389;),错误(errors))=>Err(errors),
(Err(Err),Ok()))=>Err(Err),
(Err(Err),Err(mut errors))=>{errors.combine(Err);Err(errors)}
}
})
}
}

我认为for循环很好。可能有一种方法可以使用迭代器组合器来实现这一点,但我怀疑它是否会更短或更容易理解。