You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rust嵌套迭代器中return无法从外层函数返回的问题求解

问题解决:生成数独网格时返回位置错误信息

问题背景

说明:

  • 最初的问题表述不清。我想要的是能直接返回错误的方案,但std::array::try_from_fn并不支持,当时我对此并不了解。
  • 在等待std::array::try_from_fn稳定的过程中,有很多关于替代方案和临时解决办法的优质讨论(这些方案可能会有性能损耗,但编译器大概率会优化掉)。

我编写了一个从9×9数字网格生成数独网格的函数unsolved_sudoku_from_nums。当检测到无效数字时,函数应返回该数字所在位置的信息(相关功能在注释代码中)。当前代码可以运行,但如果用注释代码替换.unwrap(),编译器会抛出一系列错误。经分析,这是因为return语句是向std::array::from_fn返回值,而非外层的unsolved_sudoku_from_nums函数。请问如何修改才能实现预期功能?谢谢。

原代码:

/// parse nums into an UnsovedSudoku, 1-9 will be parsed as values 1-9, 0 will be parsed as an unsolved cell and all
///  other values will cause the function to return an InvalidInt error.
fn unsolved_sudoku_from_nums(nums: &[[u8; 9]; 9]) -> Result<UnsolvedSudoku, InvalidInt> {
    Ok(UnsolvedSudoku (
        std::array::from_fn(|i|{
            std::array::from_fn(|j| {
                match nums[i][j] {
                    0 => WorkingCell::PossibleValues([true; 9]),
                    int => WorkingCell::Solved(
                        SudokuValue::from_int(int)
                            .unwrap()
                            // .expect(
                            //     return Err(InvalidInt{
                            //         row: i, 
                            //         column: j, 
                            //         int: nums[i][j],
                            //     })
                            // )
                        ),
                }
            })
        })
    ))
}

补充定义:

struct UnsolvedSudoku (
    [[WorkingCell; 9]; 9]
);

解决方案

方案1:手动嵌套遍历(稳定版Rust推荐)

由于std::array::from_fn不支持在闭包中向外层函数传播Result错误,最直接的方式是手动遍历9×9数组,逐个处理元素,遇到无效数字时直接返回带位置信息的错误:

fn unsolved_sudoku_from_nums(nums: &[[u8; 9]; 9]) -> Result<UnsolvedSudoku, InvalidInt> {
    // 初始化默认网格,所有单元格为待求解状态
    let mut grid = [[WorkingCell::PossibleValues([true; 9]); 9]; 9];
    
    for i in 0..9 {
        for j in 0..9 {
            let int = nums[i][j];
            grid[i][j] = match int {
                0 => WorkingCell::PossibleValues([true; 9]),
                _ => {
                    // 尝试转换数字,失败则返回带位置的错误
                    let value = SudokuValue::from_int(int)
                        .ok_or_else(|| InvalidInt {
                            row: i,
                            column: j,
                            int,
                        })?;
                    WorkingCell::Solved(value)
                }
            };
        }
    }
    
    Ok(UnsolvedSudoku(grid))
}

这种方法逻辑直观,可读性强,对于固定大小的9×9数组,编译器会完全优化循环开销,不会有性能损失。

方案2:利用迭代器与collect(函数式风格)

Rust的数组支持通过Result迭代器collect成Result<[T; N], E>,当迭代器中任何一个元素返回Err时,整个collect会立即终止并返回该错误:

fn unsolved_sudoku_from_nums(nums: &[[u8; 9]; 9]) -> Result<UnsolvedSudoku, InvalidInt> {
    let grid: Result<[[WorkingCell; 9]; 9], _> = nums
        .iter()
        .enumerate()
        .map(|(i, row)| {
            row.iter()
                .enumerate()
                .map(|(j, &int)| match int {
                    0 => Ok(WorkingCell::PossibleValues([true; 9])),
                    _ => SudokuValue::from_int(int)
                        .map(WorkingCell::Solved)
                        .ok_or_else(|| InvalidInt { row: i, column: j, int }),
                })
                // 将一行的Result迭代器收集为Result<[WorkingCell;9], InvalidInt>
                .collect::<Result<[WorkingCell; 9], _>>()
        })
        // 将所有行的Result收集为Result<[[WorkingCell;9];9], InvalidInt>
        .collect();
    
    Ok(UnsolvedSudoku(grid?))
}

这种写法偏向函数式风格,代码更紧凑,同样能实现错误的正确传播。

方案3:使用不稳定的try_from_fn(Nightly Rust)

如果可以使用Nightly版本的Rust,启用array_try_from_fn特性后,std::array::try_from_fn支持在闭包中返回Result并自动处理错误传播:

#![feature(array_try_from_fn)]

fn unsolved_sudoku_from_nums(nums: &[[u8; 9]; 9]) -> Result<UnsolvedSudoku, InvalidInt> {
    Ok(UnsolvedSudoku(
        std::array::try_from_fn(|i| {
            std::array::try_from_fn(|j| {
                match nums[i][j] {
                    0 => Ok(WorkingCell::PossibleValues([true; 9])),
                    int => SudokuValue::from_int(int)
                        .map(WorkingCell::Solved)
                        .ok_or_else(|| InvalidInt { row: i, column: j, int }),
                }
            })
        })?
    ))
}

注意该特性目前尚未稳定,不适合用于生产环境的稳定版代码。

内容的提问来源于stack exchange,提问作者Pioneer_11

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 22:42:02