Error handling 如何简化Rust中可怕的嵌套错误处理代码?
我正在写一个函数来计算生锈的Vec的a,而不使用任何外部板条箱。我正在努力学习如何尽可能地惯用这种方式,但在错误处理方面遇到了一些障碍 基本上我想做的就是,维基百科页面上提到: 一次通过就可以有效地计算总面积表 在图像上,由于x,y处的求和面积表中的值为 只是: 其中,我提供了来自网格的值,我提供了来自上一个网格的值 表的计算值。显然,如果x或y为0,那么 这些将不存在,在这种情况下,它们将替换为0 但是,值得注意的是,如果Ix,y-1不存在,即使y-1存在,那么我们使用的网格实际上是非矩形的,在这种情况下,我们希望返回一个非字符错误 在所有这些背景下,下面是代码:我需要防止减法产生溢出错误,并在特殊情况下返回非字符错误:Error handling 如何简化Rust中可怕的嵌套错误处理代码?,error-handling,rust,refactoring,Error Handling,Rust,Refactoring,我正在写一个函数来计算生锈的Vec的a,而不使用任何外部板条箱。我正在努力学习如何尽可能地惯用这种方式,但在错误处理方面遇到了一些障碍 基本上我想做的就是,维基百科页面上提到: 一次通过就可以有效地计算总面积表 在图像上,由于x,y处的求和面积表中的值为 只是: 其中,我提供了来自网格的值,我提供了来自上一个网格的值 表的计算值。显然,如果x或y为0,那么 这些将不存在,在这种情况下,它们将替换为0 但是,值得注意的是,如果Ix,y-1不存在,即使y-1存在,那么我们使用的网格实际上是非矩形的,
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本身的定义,但我不确定从哪个角度来简化它-有这么多该死的边缘案例
是否有任何内置方法可以让我逃避这种嵌套的错误检查?我可以用比这更简单的方法返回非字符错误吗?以下是一些您可以尝试的方法: 使用数组,而不是嵌套的向量。使用数组,可以保证所有行的宽度相同,并且不会出现非字符错误。但是也许你有充分的理由使用嵌套的vec,所以我的其他示例使用嵌套的vec 计算求和值的块相当长。我会这样分解它:
// 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;
而不是检验减法,更容易检查席和彝是否为非零。此外,这也是将“无”转换为错误的好方法
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链来写。他们都是惯用语,这只是偏好的问题。我更喜欢火柴,因为它感觉更简洁
let northwest = if xi == 0 {
0
} else if yi == 0 {
0
} else {
// same as above
};
以下是一些您可以尝试的东西: 使用数组,而不是嵌套的向量。使用数组,可以保证所有行的宽度相同,并且不会出现非字符错误。但是也许你有充分的理由使用嵌套的vec,所以我的其他示例使用嵌套的vec 计算求和值的块相当长。我会这样分解它:
// 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;
而不是检验减法,更容易检查席和彝是否为非零。此外,这也是将“无”转换为错误的好方法
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链来写。他们都是惯用语,这只是偏好的问题。我更喜欢火柴,因为它感觉更简洁
let northwest = if xi == 0 {
0
} else if yi == 0 {
0
} else {
// same as above
};
一个想法:将一些位抽象为函数?@JoelBerkeley好吧,当然,但这里的大多数实际工作只是一个大的加减运算,它们似乎相互耦合,在当前状态下无法真正分离。一个想法:将一些位抽象为函数?@JoelBerkeley好吧,当然,但这里的大部分实际工作只是一个大的加法和减法,而且它们之间似乎过于耦合,在当前状态下无法真正分离。