nai*_*eai 1 error-handling refactoring rust
我正在写一个函数来计算积分图的Vec<Vec<isize>>拉斯特,而无需使用任何外部包装箱。我正在尝试尽可能地习惯这样做,但是我遇到了一些错误处理的障碍。
基本上,我想做的就是在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.
Run Code Online (Sandbox Code Playgroud)
这段代码显然是sin本身的定义,但是我不确定从哪个角度简化此定义-太多了!
是否有任何内置方法可以让我摆脱这种嵌套的错误检查内容?我NonRectError可以用比这更简单的方式退货吗?
Here are some things you can try:
Use an array, not nested Vecs. With an array, you can guarantee that all the rows have the same width, and NonRectError can't happen. (But maybe you have good reasons to use nested Vecs, so the rest of my examples use nested Vecs.)
The block where you calculate summed_value is pretty long. I'd break it up like this:
// 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;
Run Code Online (Sandbox Code Playgroud)Instead of checked subtraction, it's easier to check if xi and yi are nonzero. Also, .ok_or() is a good way to convert None to an error.
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 })?
}
};
Run Code Online (Sandbox Code Playgroud)
You could also write that with an if/else chain. They're both idiomatic, it's just a matter of preference. I prefer match because it feels more concise.
let northwest = if xi == 0 {
0
} else if yi == 0 {
0
} else {
// same as above
};
Run Code Online (Sandbox Code Playgroud)| 归档时间: |
|
| 查看次数: |
124 次 |
| 最近记录: |