如何在不收集到临时向量的情况下对 Results 的迭代器执行迭代器计算? [英] How do I perform iterator computations over iterators of Results without collecting to a temporary vector?

查看:10
本文介绍了如何在不收集到临时向量的情况下对 Results 的迭代器执行迭代器计算?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在寻找一种方法来消除此示例中的临时向量分配:

I'm looking for a way to eliminate the temporary vector allocation in this example:

fn doit<T: Iterator<Item = Result<i32, &'static str>>>(name: &str, iter: T) {
    println!(
        "{}: {:?}",
        name,
        iter.collect::<Result<Vec<_>, _>>()
            .map(|v| v.into_iter().min())
    );
}

fn main() {
    let without_errors = vec![Ok(1), Ok(2), Ok(3)];
    let with_errors = vec![Ok(1), Err("error"), Ok(2)];

    doit("without errors", without_errors.into_iter());
    doit("with errors", with_errors.into_iter());
}

这是 iterator with error handling 主题的变体,除了我不想创建一个集合(所以 collect() 不太行工作),但我想对被迭代的元素执行进一步的操作.

This is a variation of the iterator with error handling theme, except that I don't want to create a collection (so collect() doesn't quite do the job), but I want to perform further operations on the elements being iterated over.

请注意,这会给出错误的结果,因为 Ok 小于 Err:

Note that this gives the wrong result because Ok is less than Err:

fn doit<T: Iterator<Item = Result<i32, &'static str>>>(name: &str, iter: T) {
    println!("{}: {:?}", name, iter.min());
}

它会意外地为 max() 给出正确的结果,但它不会停止迭代第一个错误.

It would give the right result for max() by accident, but it would not stop iterating on the first error.

推荐答案

Iterator::try_fold 为您提供所需的框架,并且从 Rust 1.27 (游乐场):

fn fold_ok<I, T, E, F>(mut iter: I, f: F) -> Result<Option<T>, E>
where
    I: Iterator<Item = Result<T, E>>,
    T: Ord,
    F: Fn(T, T) -> T,
{
    iter.try_fold(None, |r, i| {
        let i = i?;
        Ok(Some(if let Some(r) = r { f(r, i) } else { i }))
    })
}

fn main() {
    let without_errors = vec![Ok(1), Ok(2), Ok(3)];
    let with_errors = vec![Ok(1), Err("error"), Ok(2)];

    fn doit<'r, T>(name: &str, iter: T)
    where
        T: Iterator<Item = &'r Result<i32, &'static str>> + Clone,
    {
        println!("{}: {:?}", name, fold_ok(iter.cloned(), ::std::cmp::min));
    }

    doit("without errors", without_errors.iter());
    doit("with errors", with_errors.iter());
}

在此之前,我认为您唯一的选择是手动迭代 (游乐场)

Before that, I think your only option is manually iterating (Playground)

fn fold_ok<I, T, E, F>(mut iter: I, f: F) -> Result<Option<T>, E>
where
    I: Iterator<Item = Result<T, E>>,
    T: Ord,
    F: Fn(T, T) -> T,
{
    let mut result = match iter.next() {
        None => return Ok(None),
        Some(r) => r?,
    };

    for item in iter {
        result = f(result, item?);
    }

    Ok(Some(result))
}

fn main() {
    let without_errors = vec![Ok(1), Ok(2), Ok(3)];
    let with_errors = vec![Ok(1), Err("error"), Ok(2)];

    fn doit<'r, T>(name: &str, iter: T)
    where
        T: Iterator<Item = &'r Result<i32, &'static str>> + Clone,
    {
        println!(
            "{}: {:?}",
            name,
            fold_ok(iter.clone().cloned(), ::std::cmp::min)
        );
    }

    doit("without errors", without_errors.iter());
    doit("with errors", with_errors.iter());
}

这篇关于如何在不收集到临时向量的情况下对 Results 的迭代器执行迭代器计算?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆