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

Rust同一作用域双闭包可变借用问题及泛洪填充泛化需求

实现独立于数据结构的泛洪填充(Flood Fill)

我帮你把这个思路落地成可运行的代码,并且解释其中的关键细节:

核心思路就是通过分离查询和修改的行为,让泛洪填充的核心逻辑完全不依赖底层数据结构——不管你用的是一维数组、二维网格还是自定义的复杂结构,只要提供两个闭包:一个负责判断“当前位置是否可以填充”(只读查询),另一个负责“执行填充操作”(可变修改),就能复用这套泛洪逻辑。

完整可运行代码

#![feature(nll)]

// 泛洪填充核心函数,完全独立于底层数据结构
fn flood_fill<F, G>(start: i32, query: &F, mut modify: &mut G) 
where 
    F: Fn(i32) -> bool,  // 查询闭包:不可变借用数据,判断是否可填充
    G: FnMut(i32) -> (), // 修改闭包:可变借用数据,执行填充操作
{
    // 用队列实现广度优先搜索(BFS)的泛洪填充
    let mut queue = vec![start];
    
    while let Some(pos) = queue.pop() {
        // 先检查当前位置是否符合填充条件
        if query(pos) {
            // 标记为已填充,避免重复处理
            modify(pos);
            
            // 这里是一维场景的邻居扩展逻辑,你可以改成二维的上下左右等
            queue.push(pos - 1);
            queue.push(pos + 1);
        }
    }
}

// 示例:用一维数组测试泛洪填充
fn main() {
    // 模拟一维网格:0=未填充,1=障碍/已填充
    let mut grid = vec![0, 0, 1, 0, 0, 0, 1, 0];
    
    // 查询闭包:检查位置是否合法且未被填充
    let query = |pos: i32| {
        let idx = pos as usize;
        idx < grid.len() && grid[idx] == 0
    };
    
    // 修改闭包:将位置标记为已填充(设为2)
    let mut modify = |pos: i32| {
        let idx = pos as usize;
        if idx < grid.len() {
            grid[idx] = 2;
        }
    };
    
    // 从位置0开始执行泛洪填充
    flood_fill(0, &query, &mut modify);
    
    println!("填充后的网格: {:?}", grid);
    // 输出结果:[2, 2, 1, 0, 0, 0, 1, 0]
}

关键细节解释

  • 闭包的职责分离:query只做只读判断(比如边界检查、是否为可填充区域),modify只做修改操作,两者共同抽象了底层数据的访问方式,让泛洪逻辑和数据结构解耦。
  • NLL特性的作用:启用#![feature(nll)]是因为Rust的非 lexical lifetimes(NLL)允许我们同时持有同一数据的不可变查询闭包和可变修改闭包,避免了早期版本中容易出现的借用冲突问题。
  • 泛型约束的选择:F用Fn约束是因为查询闭包不需要修改自身状态;G用FnMut是因为修改闭包需要捕获并修改外部的可变变量(比如示例中的grid)。
  • 扩展性:如果要适配二维网格,只需要修改邻居扩展逻辑(比如添加上下左右四个方向),以及调整闭包中位置的处理方式(比如用(i32, i32)代替i32作为位置参数),核心的flood_fill函数完全不需要改动。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 08:41:14