我正在编写一个函数来计算Rust中Vec<Vec<isize>>
的{{3}},而无需使用任何外部包装箱。我正在尝试尽可能地习惯地做到这一点,但是我遇到了一些错误处理的障碍。
基本上我要做的就是在Wikipedia页面上提到:
总面积表可以一次有效地计算 在图像上方,因为(x,y)的总面积表中的值为 只是:
其中
i
提供网格中的值,I
提供先前的值 表的计算值。显然,如果x或y为0,则某些 这些将不存在,在这种情况下,将它们替换为0
。
但是,值得注意的是,如果I(x, y - 1)
即使存在y - 1
也不存在,那么我们正在使用的网格实际上是非矩形的,我们想返回一个在这种情况下,NonRectError
。
在所有这些背景下,下面是代码:我需要防止减法引起的溢出错误,并在特殊情况下返回NonRectError
:
fn compute_summed_area_table(grid: &Vec<Vec<isize>>) -> Result<Vec<Vec<isize>>, NonRectError> {
let mut summed_area_table =
vec![Vec::with_capacity(grid[0].len()); grid.len()];
for (yi, row) in grid.iter().enumerate() {
for (xi, &value) in row.iter().enumerate() {
let (prev_row, prev_column_idx) = (
yi.checked_sub(1).and_then(|i| summed_area_table.get(i)),
xi.checked_sub(1)
);
let summed_values =
value +
// I(x, y - 1)
match prev_row {
None => &0,
Some(prev_row_vec) => match prev_row_vec.get(xi) {
Some(v) => v,
None => return Err(NonRectError { xi, yi })
}
} +
// I(x - 1, y)
(prev_column_idx
.and_then(|i| summed_area_table[yi].get(i))
.unwrap_or(&0)) -
// I(x - 1, y - 1)
(prev_row
.map_or(&0, |r| {
prev_column_idx
.and_then(|i| r.get(i))
.unwrap_or(&0)
}));
summed_area_table[yi].push(summed_values);
}
}
Ok(summed_area_table)
}
// Omitted the definition of NonRectError here, but it is defined.
这段代码显然是sin本身的定义,但是我不确定从哪个角度简化此定义-真是太糟糕了!
是否有任何内置方法可以让我摆脱嵌套的错误检查内容?我可以用比这更简单的方法返回NonRectError
吗?
答案 0 :(得分:5)
您可以尝试以下操作:
使用数组,而不是嵌套的Vec
。使用数组,可以保证所有行的宽度相同,并且不会发生NonRectError
。 (但是也许您有充分的理由使用嵌套的Vec
,所以我的其余示例都使用嵌套的Vec
。)
您计算summed_value
的块很长。我会这样分解:
// I(x, y - 1)
let north = ...;
// I(x - 1, y)
let west = ...;
// I(x - 1, y - 1)
let northwest = ...;
let summed_values = value + north + west - northwest;
代替检查减法,更容易检查xi
和yi
是否为非零。另外,.ok_or()
是将None
转换为错误的好方法。
let northwest = match (xi, yi) {
(0, _) => 0,
(_, 0) => 0,
(_, _) => {
// We know xi and yi are nonzero, so we can subtract without checks
summed_area_table.get(yi - 1)
.and_then(|row| row.get(xi - 1))
.ok_or(NonRectError { xi, yi })?
}
};
您还可以使用if/else
链来编写代码。他们都是惯用的,这只是个喜好问题。我更喜欢match
,因为它更简洁。
let northwest = if xi == 0 {
0
} else if yi == 0 {
0
} else {
// same as above
};