gpt4 book ai didi

rust - Rust:如何在第一个Err或None上使一系列迭代器方法的导出短路?

转载 作者:行者123 更新时间:2023-12-03 11:39:33 24 4
gpt4 key购买 nike

考虑一连串的迭代器方法:

.iter().a().b().c()

其中 a产生 Option(或 Result)类型的值。有没有办法让整个链在 None产生 Err(_)(或 a)后立即返回 None(或( Err(_)))?

详细的例子

给定的函数 valid(标识无意义的输入)和 accept(一个
任意选择标准):

type T = u8;
type ERR = u8;

fn valid(x: &T) -> Result<T, ERR> {
if *x < 10 { Ok(*x) } else { Err(*x) }
}

fn accept(x: &T) -> bool {
if *x > 9 { panic!("{} should have been rejected by validator") }
*x % 2 == 0
}

我想写一个函数

fn count_accepted(data: &[T]) -> Result<usize, ERR>

哪个
  • 一旦在浏览器中遇到第一个无效元素,就返回Err(ERR)
    输入数据
  • 如果所有元素均有效,则返回包含值计数的Ok(usize)满足accept标准

  • 这是使用循环的解决方案:

    fn count_loop(data: &[T]) -> Result<usize, ERR> {
    let mut count = 0;
    for item in data {
    valid(&item)?;
    if accept(&item) { count += 1 }
    }
    Ok(count)
    }

    这些测试证明,这似乎可以按要求工作:

    macro_rules! testem {
    ($count:path) => {
    #[test] fn empty() { assert_eq!($count(&[]) , Ok(0)) }
    #[test] fn all_ok_and_accepted() { assert_eq!($count(&[2,6]) , Ok(2)) }
    #[test] fn all_ok_some_rejected() { assert_eq!($count(&[2,3]) , Ok(1)) }
    #[test] fn one_invalid() { assert_eq!($count(&[12]) , Err(12)) }
    #[test] fn stop_on_first_invalid() { assert_eq!($count(&[2,13,6,12,5]), Err(13)) }
    }
    }

    mod test_loop {testem!{super::count_loop}}

    我想了解是否/如何使用以下方法实现此行为
    迭代器而不是循环。

    考虑一个相关但更简单的问题:如果任何数据无效,则保释
    立即取出,否则将所有数据收集到向量中。换一种说法,
    从上一个问题中删除 accept条件。

    这个问题有一个令人满意的解决方案,因为 FromIterator Result的实现需要尽早终止:

    fn related(data: &[T]) -> Result<Vec<T>, ERR> {
    data.iter()
    .map(valid)
    .collect()
    }

    mod test_related {
    #[test]
    fn stop_on_first_invalid() { assert_eq!(super::related(&[2,13,6,12,5]), Err(13))}
    }

    这是 related的扩展,它通过了与 count_loop相同的测试:

    fn count_via_vec(data: &[T]) -> Result<usize, ERR> {
    Ok(data
    .iter()
    .map(valid)
    .filter(|x| x.is_err() || accept(&x.unwrap()))
    .collect::<Result<Vec<T>, ERR>>()?
    .len())
    }

    mod test_vvec {testem!{super::count_via_vec}}

    但是:就 count_loop而言,此解决方案有很多缺点:
  • 筛选条件非常嘈杂。
  • 当第一个无效项出现时,仍需要执行过滤步骤
    被识别(与原始循环实现不同):?出现
    比原应晚2行...如果有意义。
  • 不必要地填充了一个向量(除非Rust执行一些很酷的操作
    尚不了解的优化),因此空间复杂度从
    O(1)至O(N)。

  • 最后一点通常可以通过替换来解决 .collect::<Result<Vec<T>, ERR>>()?.len()).count(),但这具有
    消除对无效案件的认可的进一步有害影响:
    被简单地算作成功,正如由此证明的测试失败
    执行:

    fn count_iterate(data: &[T]) -> Result<usize, ERR> {
    Ok(data
    .iter()
    .map(valid)
    .filter(|x| x.is_err() || accept(&x.unwrap()))
    .count())
    }

    mod test_iter {testem!{super::count_iterate}}

    你能建议一些迭代器方法链中的早期返回机制吗?
    可以在这种情况下使用?

    最佳答案

    您可能正在寻找具有std::iter::Sum impl<T, U, E> Sum<Result<U, E>> for Result<T, E> where T: Sum<U> ,而对于所有基本整数也有Sum的隐含符号。

    因此,以下将正常工作:

    fn valid(x: &u32) -> Result<u32, u32> {
    if *x < 10 { Ok(1) } else { Err(*x) }
    }

    fn count(x: &[u32]) -> Result<u32, u32> {
    x.iter()
    .map(valid)
    .sum()
    }

    fn main() {
    println!("{:?}", count(&[13,1,2,3]));
    }

    正如 Sum上的文档所述,如果遇到错误,这将使迭代器短路。这将包括短路链式迭代器。

    关于rust - Rust:如何在第一个Err或None上使一系列迭代器方法的导出短路?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61824407/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com