Rust策略模式实现中返回泛型类型的语法问题
问题根源
你当前的问题核心是Strategy trait 携带泛型参数T,但你在声明Context和对应的impl块时没有将这个泛型参数纳入约束,导致do_things方法的返回类型T没有合法来源。
方案1:保留trait泛型参数
如果你的业务场景需要允许同一个策略结构体实现多种返回类型的Strategy trait,可以选择给Context增加第二个泛型参数T,修改后代码如下:
// 给Context增加泛型参数T struct Context<S, T> { strategy: S, } impl<S, T> Context<S, T> where S: Strategy<T>, // 约束S实现对应返回类型T的Strategy trait { fn do_things(&self) -> T { println!("Common preamble"); self.strategy.execute() } } trait Strategy<T> { fn execute(&self) -> T; } struct ConcreteStrategyA; struct AStruct { id: u32, } impl Default for AStruct { fn default() -> Self { AStruct { id: 1 } } } impl Strategy<AStruct> for ConcreteStrategyA { fn execute(&self) -> AStruct { println!("ConcreteStrategyA"); AStruct::default() } } struct ConcreteStrategyB; struct BStruct { id: u32, } impl Default for BStruct { fn default() -> Self { BStruct { id: 2 } } } impl Strategy<BStruct> for ConcreteStrategyB { fn execute(&self) -> BStruct { println!("ConcreteStrategyB"); BStruct::default() } } // 调用示例 fn main() { let ctx_a = Context { strategy: ConcreteStrategyA }; let res_a: AStruct = ctx_a.do_things(); println!("AStruct id: {}", res_a.id); let ctx_b = Context { strategy: ConcreteStrategyB }; let res_b: BStruct = ctx_b.do_things(); println!("BStruct id: {}", res_b.id); }
方案2:使用trait关联类型(更符合常规策略模式场景)
如果每个具体策略的返回类型是固定的,不需要支持同一个策略实现多返回类型,更推荐用关联类型代替trait泛型参数,这样可以减少泛型参数数量,代码更简洁:
struct Context<S> { strategy: S, } impl<S> Context<S> where S: Strategy, { // 直接返回策略关联的Output类型,无需额外声明泛型 fn do_things(&self) -> S::Output { println!("Common preamble"); self.strategy.execute() } } trait Strategy { // 用关联类型声明返回值类型 type Output; fn execute(&self) -> Self::Output; } struct ConcreteStrategyA; struct AStruct { id: u32, } impl Default for AStruct { fn default() -> Self { AStruct { id: 1 } } } impl Strategy for ConcreteStrategyA { type Output = AStruct; fn execute(&self) -> AStruct { println!("ConcreteStrategyA"); AStruct::default() } } struct ConcreteStrategyB; struct BStruct { id: u32, } impl Default for BStruct { fn default() -> Self { BStruct { id: 2 } } } impl Strategy for ConcreteStrategyB { type Output = BStruct; fn execute(&self) -> BStruct { println!("ConcreteStrategyB"); BStruct::default() } } // 调用示例 fn main() { let ctx_a = Context { strategy: ConcreteStrategyA }; let res_a = ctx_a.do_things(); println!("AStruct id: {}", res_a.id); let ctx_b = Context { strategy: ConcreteStrategyB }; let res_b = ctx_b.do_things(); println!("BStruct id: {}", res_b.id); }
两种方案都可以正常编译运行,你可以根据自己的业务场景选择。
内容的提问来源于stack exchange,提问作者MikeTheSapien
相关产品推荐
相关产品推荐

