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

Rust中Vec存储闭包报cannot borrow `**h` as mutable错误如何优雅解决?

报错原因

FnMut trait 的调用要求获取自身的可变借用,其核心方法签名为 fn call_mut(&mut self, args: Args) -> Output。你最初的代码中 Vec 存储的是 &dyn FnMut 不可变引用,Rust 借用规则不允许通过不可变引用修改其指向的值,因此调用闭包时会触发可变借用冲突错误。


无动态内存分配的解决方案

按适用场景从简到繁排序:

方案1:改用 Fn trait(适配当前示例,零额外开销)

你给出的示例闭包仅修改传入的参数,没有修改自身捕获的外部变量,完全符合 Fn trait 的约束。而 Fn 调用仅需要不可变借用自身,直接修改 trait 约束即可正常运行,不需要任何额外声明或分配:

fn main() {
    let hh: Vec<&dyn Fn(&mut i32)> = vec![&|i: &mut i32| {
        *i = 10;
    }];

    let mut i = 0;
    let h = &hh[0];
    h(&mut i);
    println!("{}", i);
}

方案2:存储函数指针(无捕获闭包场景,无动态分发开销)

如果你的所有闭包都没有捕获外部变量,还可以直接存储函数指针,连 trait 对象的动态分发开销都没有,也不需要引用,闭包直接存在 Vec 的栈内存中:

fn main() {
    let hh: Vec<fn(&mut i32)> = vec![|i: &mut i32| {
        *i = 10;
    }];

    let mut i = 0;
    let h = hh[0];
    h(&mut i);
    println!("{}", i);
}

方案3:需要 FnMut 场景的无堆分配方案

如果你确实需要使用捕获可变变量的 FnMut 闭包,又不想使用 Box<dyn FnMut> 做堆分配,可以通过宏批量处理闭包绑定,避免手动逐个声明的冗余:

// 批量构建FnMut Vec的宏,支持最多N个闭包,可根据需要扩展tuple实现长度
macro_rules! make_fnmut_vec {
    ($($closure:expr),*) => {{
        let mut closures = ($($closure,)*);
        let mut vec = Vec::new();
        trait AppendToVec {
            fn append_to(&mut self, vec: &mut Vec<&mut dyn FnMut(&mut i32)>);
        }
        impl<A: FnMut(&mut i32) + 'static> AppendToVec for (A,) {
            fn append_to(&mut self, vec: &mut Vec<&mut dyn FnMut(&mut i32)>) {
                vec.push(&mut self.0);
            }
        }
        impl<A: FnMut(&mut i32) + 'static, B: FnMut(&mut i32) + 'static> AppendToVec for (A, B) {
            fn append_to(&mut self, vec: &mut Vec<&mut dyn FnMut(&mut i32)>) {
                vec.push(&mut self.0);
                vec.push(&mut self.1);
            }
        }
        // 可继续扩展到3、4...个元素的tuple实现,满足实际需求
        closures.append_to(&mut vec);
        vec
    }};
}

fn main() {
    let mut count = 0;
    // 直接传入闭包即可,不需要手动声明每个闭包变量
    let mut hh = make_fnmut_vec!(
        |i: &mut i32| { *i = 10; },
        |i: &mut i32| { count += 1; *i += count; }
    );

    let mut i = 0;
    hh[0](&mut i);
    println!("{}", i); // 输出10
    hh[1](&mut i);
    println!("{}", i); // 输出11
}

这个方案所有闭包都存储在栈上的 tuple 中,没有任何堆内存分配,宏自动完成变量绑定和 trait 对象转换,写法简洁。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 20:15:02