在Rust中如何存储异构函数组成的延迟执行调用链?
实现方案
Rust作为静态类型语言,无法直接用Vec存储类型异构的函数,你可以根据场景选择以下两种方案实现需求:
方案1:编译期类型安全的零开销实现
这种方案通过递归泛型结构体实现,所有类型检查在编译期完成,无任何运行时开销,适合函数链结构在编译期就可以确定的场景。
核心实现代码
// 终止标记:代表函数链的末尾 struct Nil; // 函数链节点:存储当前函数和下一段链 struct Cons<S, T, N> { func: fn(S) -> T, next: N, } // 调用trait:统一不同节点的调用行为 trait Call<Input> { type Output; fn call(&self, input: Input) -> Self::Output; } // 终止节点的调用实现:直接返回输入值 impl<I> Call<I> for Nil { type Output = I; fn call(&self, input: I) -> Self::Output { input } } // 普通节点的调用实现:先执行当前函数,再把输出传给下一段链 impl<S, T, N, O> Call<S> for Cons<S, T, N> where N: Call<T, Output = O>, { type Output = O; fn call(&self, input: S) -> Self::Output { let next_input = (self.func)(input); self.next.call(next_input) } } // 扩展方法:方便链式拼接函数 impl<S, T, N> Cons<S, T, N> { fn then<U>(self, func: fn(T) -> U) -> Cons<T, U, Self> { Cons { func, next: self } } } // 构造函数链的入口 fn func_chain<S, T>(func: fn(S) -> T) -> Cons<S, T, Nil> { Cons { func, next: Nil } }
使用示例
fn main() { // 构造函数链:i32 -> String -> u8 -> String -> i32 let chain = func_chain(|x: i32| x.to_string()) .then(|s| s.parse::<u8>().unwrap()) .then(|n| n.to_string()) .then(|s| s.parse::<i32>().unwrap()); // 执行调用 let res = chain.call(123); println!("执行结果:{}", res); // 输出 123 }
这种方案下函数链的类型会在编译期自动推导,任何输入输出不匹配的错误都会在编译期被捕获,完全不需要运行时类型检查。
方案2:运行时动态可修改的类型擦除实现
如果你需要在运行时动态添加/删除函数,可以通过类型擦除的方式实现,会有少量运行时开销,且需要处理类型转换失败的情况:
use std::any::Any; struct DynFuncChain { funcs: Vec<Box<dyn FnOnce(Box<dyn Any>) -> Result<Box<dyn Any>, &'static str>>>, } impl DynFuncChain { fn new() -> Self { Self { funcs: Vec::new() } } fn add<S: 'static, T: 'static>(&mut self, func: fn(S) -> T) { self.funcs.push(Box::new(move |input: Box<dyn Any>| { let s = input.downcast::<S>().map_err(|_| "类型转换失败")?; Ok(Box::new(func(*s))) })); } fn call<I: 'static, O: 'static>(self, input: I) -> Result<O, &'static str> { let mut res: Box<dyn Any> = Box::new(input); for func in self.funcs { res = func(res)?; } res.downcast::<O>().map(|o| *o).map_err(|_| "最终结果类型不匹配") } } // 使用示例 fn main() { let mut chain = DynFuncChain::new(); chain.add(|x: i32| x.to_string()); chain.add(|s: String| s.parse::<u8>().unwrap()); chain.add(|n: u8| n.to_string()); chain.add(|s: String| s.parse::<i32>().unwrap()); let res = chain.call(123).unwrap(); println!("执行结果:{}", res); // 输出 123 }
内容的提问来源于stack exchange,提问作者Migwell
相关产品推荐
相关产品推荐

