如何在Rust中实现类似boost::yap的带transform功能的表达式模板
问题解答:Rust实现带transform特性的表达式模板
核心结论
Rust不存在原理性障碍,可以实现带transform特性的表达式模板,完全可以支撑类似boost::yap的设计模式。
问题1解决:编译错误与闭包适配多类型的实现
你的编译错误来源于trait Transform的泛型设计缺陷:你将闭包的入参类型绑死在了当前实现类型&Self上,递归到子节点U类型时,闭包无法适配&U类型的入参。
正确的修改方案如下:
#![feature(specialization)] // 开启特化特性用于解决第二个问题 use std::ops::Neg; enum E<U> { Terminal(U), Neg(U) } impl<U> Neg for E<U> { type Output = E<E<U>>; fn neg(self) -> Self::Output { E::Neg(self) } } trait Transform { fn transform<R, F: FnMut(&Self) -> Option<R>>(&self, f: F) -> Option<R>; } // 给所有类型默认实现Transform,对应终端节点逻辑 impl<T> Transform for T { default fn transform<R, F: FnMut(&Self) -> Option<R>>(&self, mut f: F) -> Option<R> { f(self) } } // 特化E<U>的Transform实现 impl<U: Transform + Neg<Output = E<U>>> Transform for E<U> { fn transform<R, F: FnMut(&Self) -> Option<R>>(&self, mut f: F) -> Option<R> { // 先尝试匹配当前节点 if let Some(res) = f(self) { return Some(res); } match self { E::Terminal(v) => v.transform(f), E::Neg(x) => x.transform(f).map(Neg::neg) } } }
修改后闭包可以自动适配任意嵌套层级的E类型和终端值类型,无需手动处理类型匹配。
问题2解决:免除用户手动实现Transform的需求
使用上述代码中的Rust特化(specialization)特性,我们可以给所有类型提供默认的Transform实现,用户无需再为i32、u32这类基础类型手动写空实现。
目前特化特性还未稳定,需要使用nightly版本Rust。如果你一定要在稳定版实现,可以使用宏批量为所有基础类型生成Transform实现,虽然不够灵活但可以满足大部分场景需求:
// 稳定版替代方案:用宏批量实现基础类型的Transform macro_rules! impl_transform_for { ($($t:ty)*) => { $(impl Transform for $t { fn transform<R, F: FnMut(&Self) -> Option<R>>(&self, mut f: F) -> Option<R> { f(self) } })* } } impl_transform_for! { i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 bool &str String }
修正后测试用例
fn main() { // 无需再手动impl Transform for i32 let y = E::Neg(E::Neg(E::Neg(E::Terminal(42)))); // 计数嵌套层数 let mut count = 0; y.transform(|x| { match x { E::Neg(_) => { count += 1; None } _ => Some(()) } }); assert_eq!(count, 3); // 替换终端值 let expr = y.transform(|x| { match x { E::Terminal(_) => Some(E::Terminal(5)), _ => None } }).unwrap(); // 表达式求值 let result = expr.transform(|x| { match *x { E::Terminal(v) => Some(v), _ => None } }).unwrap(); assert_eq!(result, -5); }
内容的提问来源于stack exchange,提问作者joergbrech
相关产品推荐
相关产品推荐

