如何编写可返回自身的函数,支持foo()()...()形式的链式调用?
Rust实现自返回函数与链式调用求和
核心思路
Rust的类型系统不支持直接定义递归的函数类型,也没有C#的dynamic动态类型绕过检查,因此需要通过newtype包装结构体的方式实现自返回逻辑,求和场景下我们还会把累加值存在结构体内部,避免使用全局可变变量。
1. 基础版:无参数自返回函数
如果仅需要实现foo()()...()的无限链式调用,有两种实现方式:
(1)Nightly版本(支持()直接调用)
需要启用Rust不稳定特性,实现Fn系列trait:
// 顶部开启特性 #![feature(fn_traits, unboxed_closures)] #[derive(Copy, Clone)] struct SelfFunc(fn() -> SelfFunc); // 实现FnOnce/FnMut/Fn trait支持()调用 impl FnOnce<()> for SelfFunc { type Output = SelfFunc; extern "rust-call" fn call_once(self, _args: ()) -> Self::Output { self.0() } } impl FnMut<()> for SelfFunc { extern "rust-call" fn call_mut(&mut self, _args: ()) -> Self::Output { self.0() } } impl Fn<()> for SelfFunc { extern "rust-call" fn call(&self, _args: ()) -> Self::Output { self.0() } } fn main() { let foo = SelfFunc(|| foo); // 支持无限链式调用 foo()()()()(); }
(2)稳定版兼容实现
不需要不稳定特性,通过自定义方法调用即可:
#[derive(Copy, Clone)] struct SelfFunc(fn() -> SelfFunc); impl SelfFunc { fn call(self) -> Self { self.0() } } fn main() { let foo = SelfFunc(|| foo); foo.call().call().call(); }
2. 进阶版:链式调用求和
完全实现你要的foo(1)(2)(3)() = 6的效果:
Nightly版本(原生支持()调用)
#![feature(fn_traits, unboxed_closures)] #[derive(Copy, Clone)] struct SumFunc { sum: i32, } // 处理传入整数的调用:累加后返回自身 impl FnOnce<(i32,)> for SumFunc { type Output = SumFunc; extern "rust-call" fn call_once(self, args: (i32,)) -> Self::Output { SumFunc { sum: self.sum + args.0 } } } impl FnMut<(i32,)> for SumFunc { extern "rust-call" fn call_mut(&mut self, args: (i32,)) -> Self::Output { self.sum += args.0; *self } } impl Fn<(i32,)> for SumFunc { extern "rust-call" fn call(&self, args: (i32,)) -> Self::Output { SumFunc { sum: self.sum + args.0 } } } // 处理无参调用:返回最终累加结果 impl FnOnce<()> for SumFunc { type Output = i32; extern "rust-call" fn call_once(self, _args: ()) -> Self::Output { self.sum } } impl FnMut<()> for SumFunc { extern "rust-call" fn call_mut(&mut self, _args: ()) -> Self::Output { self.sum } } impl Fn<()> for SumFunc { extern "rust-call" fn call(&self, _args: ()) -> Self::Output { self.sum } } fn main() { let foo = SumFunc { sum: 0 }; let res = foo(1)(2)(3)(); assert_eq!(res, 6); println!("{}", res); // 输出6 }
稳定版兼容实现
用自定义方法替代原生()调用,不需要依赖不稳定特性:
#[derive(Copy, Clone)] struct SumFunc { sum: i32, } impl SumFunc { fn new() -> Self { SumFunc { sum: 0 } } // 传入数字累加,返回新的实例 fn add(self, num: i32) -> Self { SumFunc { sum: self.sum + num } } // 结束调用,返回结果 fn result(self) -> i32 { self.sum } } fn main() { let foo = SumFunc::new(); let res = foo.add(1).add(2).add(3).result(); assert_eq!(res, 6); }
补充说明
C#中可以直接用递归委托+dynamic类型实现的核心是运行时类型检查,Rust为了保证内存安全和零成本抽象,所有类型必须在编译期确定,因此必须通过newtype包装的方式构造合法的递归类型。
内容的提问来源于stack exchange,提问作者alordash
相关产品推荐
相关产品推荐

