Rust带闭包的泛型有限状态机实现问题求助
解决Rust泛型闭包FSM的两个问题
问题1:移除多余的PhantomData
你需要调整结构体的泛型参数定义,让输入、输出类型直接通过闭包的签名关联,而非单独声明未使用的泛型参数。
原问题原因
当泛型参数(比如你的A、B)在结构体中没有被直接使用时,Rust编译器会判定它们为多余参数,因此要求添加PhantomData来“占位”。但实际上这些类型完全可以通过闭包的函数签名推导出来。
修正后的结构体定义
// 直接将输入(I)、状态(S)、输出(O)作为泛型参数,闭包类型关联这些参数 struct FSM<I, S, O, U, Oup> where U: Fn(I, S) -> S, Oup: Fn(I, S) -> O, { update: U, output: Oup, state: S, } impl<I, S, O, U, Oup> FSM<I, S, O, U, Oup> { // 构造函数:直接推导泛型参数,无需手动指定PhantomData fn new(initial_state: S, update: U, output: Oup) -> Self { Self { state: initial_state, update, output, } } // 运行FSM的示例方法 fn step(&mut self, input: I) -> O where S: Clone, { let current_state = self.state.clone(); let output = (self.output)(input.clone(), current_state); self.state = (self.update)(input, self.state); output } }
这样调整后,I(输入类型)、O(输出类型)都通过闭包U、Oup的签名被直接使用,编译器不再需要PhantomData来满足泛型参数的使用要求。
问题2:修复product方法的闭包类型不匹配错误
product方法的核心问题是:闭包是匿名类型,无法提前通过泛型参数U3、O3声明。解决方法是使用impl Trait来指定返回值中闭包的 trait 约束,而非尝试命名匿名的闭包类型。
修正后的product方法实现
impl<I, S1, O1, U1, Oup1> FSM<I, S1, O1, U1, Oup1> where U1: Clone, Oup1: Clone, I: Clone, { // 组合两个FSM为乘积FSM:状态为元组,输出为元组,输入共享同一类型 fn product<S2, O2, U2, Oup2>(self, other: FSM<I, S2, O2, U2, Oup2>) -> FSM<I, (S1, S2), (O1, O2), impl Fn(I, (S1, S2)) -> (S1, S2), impl Fn(I, (S1, S2)) -> (O1, O2)> where U2: Clone, Oup2: Clone, { let update_self = self.update; let update_other = other.update; let output_self = self.output; let output_other = other.output; FSM::new( (self.state, other.state), // 组合update闭包:分别更新两个子状态 move |input, (s1, s2)| { let new_s1 = update_self(input.clone(), s1); let new_s2 = update_other(input, s2); (new_s1, new_s2) }, // 组合output闭包:分别生成两个子输出 move |input, (s1, s2)| { let out1 = output_self(input.clone(), s1); let out2 = output_other(input, s2); (out1, out2) }, ) } }
关键说明
- 使用
impl Fn(...) -> ...作为返回值中闭包的类型,告诉编译器:返回的闭包实现了对应的Fntrait,无需显式命名匿名类型。 - 添加
Clone约束:因为闭包需要捕获并复用原FSM的update和output闭包,所以需要这些闭包支持克隆(如果你的闭包无法克隆,可以改用Arc来共享)。 - 输入类型
I添加Clone约束:因为需要将输入传递给两个子FSM的闭包。
测试示例
fn main() { // 第一个FSM:计数器,输入为bool,true则+1,输出当前值 let mut counter_fsm = FSM::new( 0, |inc: bool, state: i32| if inc { state + 1 } else { state }, |_inc: bool, state: i32| state, ); // 第二个FSM:布尔翻转器,输入为bool,true则翻转状态,输出当前状态 let mut toggle_fsm = FSM::new( false, |toggle: bool, state: bool| if toggle { !state } else { state }, |_toggle: bool, state: bool| state, ); // 组合为乘积FSM let mut product_fsm = counter_fsm.product(toggle_fsm); // 测试步骤 assert_eq!(product_fsm.step(true), (1, true)); assert_eq!(product_fsm.step(false), (1, true)); assert_eq!(product_fsm.step(true), (2, false)); }
内容的提问来源于stack exchange,提问作者lighthouse
相关产品推荐
相关产品推荐

