“None”上的 Rust 跳过循环,否则继续计算

问题描述

我有一个嵌套循环,我想在其中检查某个条件是否适用于 usize 值表。但是,该表可能仅被部分填充——因此它实际上是一个包含 Option<usize> 变量的表。当至少缺少一个值时,我不认为违反了条件,因此希望继续处理下一组值。

目前我是这样做的:

for i in 0..n {
    for j in 0..n {
        for k in 0..n {
            let v_ij = match table[i][j] {
                None => { continue; },Some(val) => { val }
            };

            let v_jk = match table[j][k] {
                None => { continue; },Some(val) => { val }
            };

            let res_left = match table[v_ij][k] {
                None => { continue; },Some(val) => { val }
            };

            let res_right = match table[i][v_jk] {
                None => { continue; },Some(val) => { val }
            };

            if res_left != res_right {
                return false;
            }
        }
    }
}

(对于上下文:计算是检查部分岩浆是否具有缔合性,但这对于问题并不重要。)

有没有一种惯用的方法来替换所有这些匹配项?在 Haskell 中,使用 Maybe monad,我相信我可以将这段代码包装到一个 do 块中,以便自动传播 None 值。我尝试使用 table[i][j].unwrap_or({continue;}) 但这会贪婪地评估 continue;使用 table[i][j].unwrap_or_else({continue;}) 会出现语法错误

解决方法

在选项上使用 ? 运算符为您执行 continue,并使用 itertools 来构建迭代器,您可以采用函数式方法:

use itertools::Itertools;

let has_false = (0..n)
    .permutations(3)
    .filter_map(|v| {
        let (i,j,k) = (v[0],v[1],v[2]);
        let v_ij = table[i][j]?;
        let v_jk = table[j][k]?;
        Some((table[v_ij][k]?,table[i][v_jk]?))
    })
    .any(|(res_left,res_right)| res_left != res_right);
,

在这种情况下,为了限制重复并提高清晰度,我可能会使用宏:

macro_rules! unwrap_or_continue {
    ($opt: expr) => {
        match $opt {
            Some(v) => v,None => {continue;}
        }
    }
}

loop_unwrap crate 实现了类似但更复杂的东西。

因此您的每个测试都会减少:

for i in 0..n {
    for j in 0..n {
        for k in 0..n {
            let v_ij = unwrap_or_continue!(table[i][j]);
            let v_jk = unwrap_or_continue!(table[j][k]);
            let res_left = unwrap_or_continue!(table[v_ij][k]);
            let res_right = unwrap_or_continue!(table[i][v_jk]);
            if res_left != res_right {
                return false;
            }
        }
    }
}