如何简化Rust中这种可怕的嵌套错误处理代码?

我正在编写一个函数来计算Rust中Vec<Vec<isize>>的{​​{3}},而无需使用任何外部包装箱。我正在尝试尽可能地习惯地做到这一点,但是我遇到了一些错误处理的障碍。

基本上我要做的就是在Wikipedia页面上提到:

  

总面积表可以一次有效地计算   在图像上方,因为(x,y)的总面积表中的值为   只是:

     

如何简化Rust中这种可怕的嵌套错误处理代码?

     

其中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吗?

beijiao_1608 回答:如何简化Rust中这种可怕的嵌套错误处理代码?

您可以尝试以下操作:

  1. 使用数组,而不是嵌套的Vec。使用数组,可以保证所有行的宽度相同,并且不会发生NonRectError。 (但是也许您有充分的理由使用嵌套的Vec,所以我的其余示例都使用嵌套的Vec。)

  2. 您计算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;
    
  3. 代替检查减法,更容易检查xiyi是否为非零。另外,.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
    };
    
本文链接:https://www.f2er.com/3085037.html

大家都在问