Rust中为子Trait实现父Trait并向上转型的编译错误修复请求
Rust中为子Trait实现父Trait并向上转型的编译错误修复请求
我来帮你拆解这个问题的根源,然后给出两种贴合你需求的修复方案~
问题根源分析
你当前的代码是为**dyn GoesUp和dyn GoesDown这两个trait对象类型**实现了GoesSomewhere,但编译器报错的核心原因是:
get_up()返回的impl GoesUp是具体类型(比如Escalators),而非trait对象(dyn 版本)- 具体类型本身并没有实现
GoesSomewhere,只有它们对应的trait对象(dyn GoesUp/dyn GoesDown)才实现了这个超级trait - 直接把具体类型强转成
&dyn GoesSomewhere时,编译器找不到具体类型到GoesSomewhere的实现路径
修复方案1:为所有子Trait实现者自动绑定超级Trait
通过全域实现(Blanket Implementation),让任何实现了GoesUp/GoesDown的类型自动获得GoesSomewhere的实现,这是最简洁的方案:
trait GoesUp { fn goUp(&mut self) -> (); } trait GoesDown { fn goDown(&mut self) -> (); } trait GoesSomewhere { fn goSomewhere(&mut self) -> (); } // 让所有实现GoesUp的类型自动实现GoesSomewhere impl<T: GoesUp> GoesSomewhere for T { fn goSomewhere(&mut self) { self.goUp(); } } // 让所有实现GoesDown的类型自动实现GoesSomewhere impl<T: GoesDown> GoesSomewhere for T { fn goSomewhere(&mut self) { self.goDown(); } } // 以下是你原有的结构体、实现和函数,无需修改 struct Escalators { height : i32 } struct Slide { height : i32 } impl GoesUp for Escalators { fn goUp(&mut self) { self.height += 1; } } impl GoesDown for Slide { fn goDown(&mut self) { self.height -= 1; } } fn get_up() -> impl GoesUp { Escalators{ height : 1} } fn get_down() -> impl GoesDown { Slide{ height : 1 } } fn move_escalators() -> () { let mut x = get_up(); x.goUp(); let casted = &mut x as &mut dyn GoesSomewhere; casted.goSomewhere(); } fn move_slide() -> () { let mut x = get_down(); x.goDown(); let casted: Box<dyn GoesSomewhere> = Box::new(x); casted.goSomewhere(); } // 你提到的skip函数也能正常工作 fn skip(mut param: Box<dyn GoesSomewhere>) { param.goSomewhere(); } fn move_slide_with_skip() -> () { let mut x = get_down(); x.goDown(); let casted: Box<dyn GoesSomewhere> = Box::new(x); casted.goSomewhere(); skip(casted); }
注意:如果有类型同时实现了GoesUp和GoesDown,这个方案会出现编译冲突(编译器不知道该用哪个GoesSomewhere实现)。如果你的业务场景中不会有这种重叠类型,这个方案是最优选择。
修复方案2:保留原Trait对象实现,正确转换类型
如果你想坚持只给dyn GoesUp/dyn GoesDown实现GoesSomewhere,那需要先把具体类型转换成对应的子Trait对象,再转成dyn GoesSomewhere:
// 保留你原有的Trait定义与对象实现 trait GoesUp { fn goUp(&mut self) -> (); } trait GoesDown { fn goDown(&mut self) -> (); } trait GoesSomewhere { fn goSomewhere(&mut self) -> (); } impl GoesSomewhere for dyn GoesUp { fn goSomewhere(&mut self) { self.goUp() } } impl GoesSomewhere for dyn GoesDown { fn goSomewhere(&mut self) { self.goDown() } } // 原结构体与实现不变 struct Escalators { height : i32 } struct Slide { height : i32 } impl GoesUp for Escalators { fn goUp(&mut self) { self.height += 1; } } impl GoesDown for Slide { fn goDown(&mut self) { self.height -= 1; } } fn get_up() -> impl GoesUp { Escalators{ height : 1} } fn get_down() -> impl GoesDown { Slide{ height : 1 } } // 修正类型转换逻辑:先转成子Trait对象,再转超级Trait对象 fn move_escalators() -> () { let mut x = get_up(); x.goUp(); let casted = &mut x as &mut dyn GoesUp as &mut dyn GoesSomewhere; casted.goSomewhere(); } fn move_slide() -> () { let mut x = get_down(); x.goDown(); let casted: Box<dyn GoesSomewhere> = Box::new(x) as Box<dyn GoesDown> as Box<dyn GoesSomewhere>; casted.goSomewhere(); } // skip函数与调用逻辑正常工作 fn skip(mut param: Box<dyn GoesSomewhere>) { param.goSomewhere(); } fn move_slide_with_skip() -> () { let mut x = get_down(); x.goDown(); let casted: Box<dyn GoesSomewhere> = Box::new(x) as Box<dyn GoesDown> as Box<dyn GoesSomewhere>; casted.goSomewhere(); skip(casted); }
这个方案严格遵循了你最初的设计思路:只有Trait对象才实现GoesSomewhere,具体类型本身不直接绑定。转换时显式经过子Trait对象的步骤,编译器就能找到对应的GoesSomewhere实现。
内容来源于stack exchange
相关产品推荐
相关产品推荐

