【问题标题】:Can I return immediately when meets None while function chaining?函数链接时遇到 None 可以立即返回吗?
【发布时间】:2021-11-16 20:29:57
【问题描述】:

Problem.
我对此很好奇,因为如果可以的话,我认为这段代码中不需要 if 的东西。
我特别想要 .filter_map(|ch| ch.to_digit(10)).
ch.to_digit() 如果 ch 不是数字则返回 None 。然后我想返回 false。
如果我能做到这一点,我想我不需要if !code.chars().all(|ch| ch.is_digit(10) || ch.is_whitespace()) 这张支票。 (我只是想知道如果在链接中进行检查,我可以这样做。)

如果不允许,有没有办法在函数链中进行异常检查?
谢谢。

/// Check a Luhn checksum.
pub fn is_valid(code: &str) -> bool {
    if code.trim().len() <= 1 {
        return false;
    }
    if !code.chars().all(|ch| ch.is_digit(10) || ch.is_whitespace()) {
        return false;
    }

    code.chars()
        .rev()
        .filter_map(|ch| ch.to_digit(10))
        .enumerate()
        .map(|( i, n)|
            match i % 2 {
                0 => n,
                _ if n == 9 => n,
                _ => (n * 2) % 9,
            }
        )
        .sum::<u32>() % 10 == 0
}

【问题讨论】:

  • 你能改写你的问题吗?我不明白你的问题,对不起。你的问题是什么?你想达到什么目标?也许写一些伪代码或类似的。

标签: function methods rust


【解决方案1】:

函数链接时遇到None可以立即返回吗?

不是真的。你可以mapOption(而不是filter_map)然后collectIterator&lt;Option&lt;_&gt;&gt;Option&lt;Vec&lt;_&gt;&gt;

let items = vec![0_u16, 1, 2];

let res: Option<Vec<u16>> = items
    .iter()
    .map(|x| x.checked_add(1))
    .collect();

assert_eq!(res, Some(vec![1, 2, 3]));

let res: Option<Vec<u16>> = items
    .iter()
    .map(|x| x.checked_sub(1))
    .collect();

assert_eq!(res, None);

如果你最后有一个None,你就可以保释了。

但老实说,我只会使用沼泽标准 for 循环,例如:

let mut sum = 0;
for (i, n) = code.chars().rev().map(|ch| ch.to_digit(10)).enumerate() {
    sum += match (i % 2, n) {
        (_, None) => return false;
        (0, Some(n)) => n,
        (_, Some(9)) => 9,
        (_, Some(n)) => (n * 2) % 9,
    }
}
sum % 10 == 0

如果不允许,有没有办法在函数链中进行异常检查?

不知道你的意思。

【讨论】:

  • "有没有办法在函数链中进行异常检查?"在像 Swift 这样的语言中,在这里使用throw 来提前中止是很常见的。我相信这就是OP所指的。 (但在 Rust 中,我同意 for 循环绝对是最好的方法。)
  • take_while 将允许立即停止
  • @Stargateur 的目标是表明该序列在这种情况下无效,据我所知,take_while 不会这样做,除非您也将map 发送到Option ,然后你仍然需要迭代整个事情以发现有一个None,此时我看不到与跳过take_while相比的增益。
  • @Stargateur 原发帖者明确表示他们的目标是删除对序列的预检查(第 5-7 行),所以这不是猜测,重点是避免重复两次。
  • 我同意@Masklinn,但我不明白为什么在循环中返回很好,而不是在链式方法中。
【解决方案2】:

你可以用try_fold:

pub fn is_valid(code: &str) -> bool {
    code.chars()
        .rev()
        .try_fold((0, 0), |acc, ch|
            // `acc.0` enumerates the valid digits
            // `acc.1` accumulates the sum
            if ch.is_whitespace() {
                Some (acc)
            } else {
                ch.to_digit (10).map (|n|
                    match acc.0 % 2 {
                        0 => (acc.0+1, acc.1 + n),
                        _ if n == 9 => (acc.0+1, acc.1 + n),
                        _ => (acc.0+1, acc.1 + (n*2)%9),
                    })
            })
        .map (|acc| acc.1 % 10 == 0)
        .unwrap_or (false)
}

Playground

但为了便于阅读,我会使用 @Masklinn 的直接 for 循环。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-02-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多