如何将一系列 Result<(A, B), E> 解压缩到 (Vec<A>, Vec<B>) 并在第一个错误时停止?

nov*_*ean 5 iterator rust

我想做这样的事情:

enum MyEnum {
    Foo(Vec<Stuff>),
    // ...
}

impl MyEnum {
    fn do_sth(&self) -> Result<Bar, E> {
        match *self {
            MyEnum::Foo(ref vec) => {
                let (a, b): (Vec<A>, Vec<B>) = vec
                    .iter()
                    .map(|thing| thing.make_a_tuple(arg)) // returns Result<(A, B), E>
                    .collect::<Result<_, _>>()? // stop on first error
                    .unzip();

                // use a and b
            }

            // other cases
        }

        // ...
    }
}
Run Code Online (Sandbox Code Playgroud)

这无法与error: the type of this value must be known in this context. 通过反复试验,我让它像这样编译

    fn do_sth(&self) -> Result<Bar, E> {
        match *self {
            MyEnum::Foo(ref vec) => {
                let (a, b): (Vec<A>, Vec<B>) = vec
                    .iter()
                    .map(|thing| thing.make_a_tuple(arg))
                    .collect::<Result<Vec<_>, _>>()?
                    .into_iter()
                    .unzip();

                // use a and b
            }

            // other cases
        }
    }
Run Code Online (Sandbox Code Playgroud)

但是,我想避免不必要的Vec<(A, B)>.

是否可以在没有中间分配的情况下做到这一点?我确信我可以自己用循环来做到这一点,但我更愿意学习 Rusty 的方式。

She*_*ter 9

我经常遇到Results 迭代器的此类问题,因此我在名为 的标准库中添加了一个(私有)辅助类型ResultShunt这为sSum和sProductResult的实现提供了动力。

我还将它提交给 itertools,以便可以重用:

use itertools; // 0.10.1

fn main() {
    let iter_source: Vec<Result<(i32, i32), bool>> = vec![Ok((1, 2)), Err(false), Ok((3, 4))];

    let z = itertools::process_results(iter_source, |iter| iter.unzip::<_, _, Vec<_>, Vec<_>>());

    println!("{:?}", z);
}
Run Code Online (Sandbox Code Playgroud)