Rust 在 "None" 上跳过循环,否则继续计算

Rust skip loop on "None" else move forward with computation

我有一个嵌套循环,我想在其中检查某个条件是否适用于 table 的 usize 值。然而,table 可能只被部分填充——所以它实际上是 table 个 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;}) 会出现语法错误。

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

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;
            }
        }
    }
}

在选项上使用 ? 运算符为您执行 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);