Rust中能否无需Box实现递归匿名函数?实现func_n功能
问题解答
1. 该功能可以实现
不需要使用Box就能完成需求,核心是避免创建多个不同类型的闭包。
2. 实现方法
你的原代码报错是因为每次循环生成的闭包都是不同的匿名类型,Rust静态类型系统不允许将不同类型的值赋值给同一个变量。下面是两种可行的无Box实现:
方法一:在单闭包内完成循环调用
这是最直接且高效的方式,返回的闭包内部直接重复调用f共n次:
pub fn func_n<T, F: FnMut(T) -> T>(n: u8, mut f: F) -> impl FnMut(T) -> T { move |mut x| { for _ in 0..n { x = f(x); } x } }
- 原理:
move闭包捕获外部的f,在内部通过循环完成n次调用逻辑,整个逻辑只对应一个闭包类型,完全符合impl FnMut(T) -> T的返回要求。 - 使用示例:
let add_one = |x: i32| x + 1; let add_two = func_n(2, add_one); assert_eq!(add_two(3), 5); // 等价于 add_one(add_one(3))
方法二:编译期常量次数的函数组合(可选)
如果n是编译期已知的常量,可以用类型级编程实现真正的函数组合,但这种方式仅适用于n固定的场景:
use std::ops::FnMut; pub trait ComposeFn<F> { type Output: FnMut(<F as FnMut>::Input) -> <F as FnMut>::Output; fn compose(self, f: F) -> Self::Output; } impl<T, F: FnMut(T) -> T> ComposeFn<F> for F { type Output = impl FnMut(T) -> T; fn compose(mut self, mut f: F) -> Self::Output { move |x| self(f(x)) } } // 编译期递归组合 pub fn func_n_const<T, F: FnMut(T) -> T, const N: usize>(mut f: F) -> impl FnMut(T) -> T { if N == 0 { return |x| x; } let composed = func_n_const::<T, F, { N - 1 }>(f); composed.compose(f) }
- 使用示例:
let add_one = |x: i32| x + 1; let add_three = func_n_const::<_, _, 3>(add_one); assert_eq!(add_three(0), 3);
内容的提问来源于stack exchange,提问作者Djd An
相关产品推荐
相关产品推荐

