问题描述
我有一个嵌套循环,我想在其中检查某个条件是否适用于 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;
}
}
}
}