如何在Rust中分割结果向量?

6

基本上,我在寻找Rust中等价于partitionEithers的函数,即将Vec<Result<A, B>>转换成Result<Vec<A>, Vec<B>>

我知道可以通过使用collect::<Result<Vec<A>, B>>Vec<Result<A, B>>转换为Result<Vec<A>, B>,但是当我尝试使用collect::<Result<Vec<A>, Vec<B>>>时,会得到一个错误,表明缺少该实现。

此外,我知道这可以通过变异来完成,但我想知道是否有任何不可变的替代方案?


在Rust中,partitionEithers的等效函数将是fn(Vec<Result<A, B>>) -> (Vec<A>, Vec<B>) -- 请注意,Result是一个枚举类型,而Result<Vec<A>, Vec<B>>可以包含_要么_ Vec<A> 要么 Vec<B>,但不能同时包含两者。 - EvilTak
@Stargateur,你能解释一下为什么这没有意义吗? - Wong Jia Hau
期望的错误类型是 Vec<B> - Wong Jia Hau
1
哦,我昨天一定很累了 :p - Stargateur
2个回答

10

您可以使用 partition() 方法进行分区,在您的特定情况下,可以使用itertools中的partition_map()

use itertools::{Either, Itertools};
fn main() {
    let successes_and_failures = vec![Ok(1), Err(false), Err(true), Ok(2)];

    let (successes, failures): (Vec<_>, Vec<_>) =
        successes_and_failures
            .into_iter()
            .partition_map(|r| match r {
                Ok(v) => Either::Left(v),
                Err(v) => Either::Right(v),
            });

    assert_eq!(successes, [1, 2]);
    assert_eq!(failures, [false, true]);
}

谢谢,我应该早点采用 itertools - Wong Jia Hau

2

itertools crate有一个专用的方法,用于将Iterator<Item = Result<T, E>>分割成一个元组集合(Collection<T>, Collection<E>),其中"Collection"可以是您选择的实现了Extend trait的类型,如VecHashSet

https://docs.rs/itertools/0.11.0/itertools/trait.Itertools.html#method.partition_result

use itertools::Itertools;

fn main() {
    let successes_and_failures = vec![Ok(1), Err(false), Err(true), Ok(2)];

    let (successes, failures): (Vec<_>, Vec<_>) =
        successes_and_failures.into_iter().partition_result();

    assert_eq!(successes, [1, 2]);
    assert_eq!(failures, [false, true]);
}

在您的迭代器的Item类型不完全是Result而是其他类型时,为了更加通用化,还有partition_map,您可以提供一个闭包来决定每个元素应该属于第一个输出集合还是第二个输出集合。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接