如何将Box<dyn Trait>引用传入接受实现该Trait泛型参数的函数
错误原因
- 你定义的
do_something是泛型函数,Rust的泛型参数默认携带Sized(编译期固定大小)约束,而dyn MyTrait是动态大小类型,不满足Sized要求,编译器无法将泛型参数T推导为dyn MyTrait,因此抛出类型注解缺失的错误。 - 泛型函数默认走静态分发,编译期必须确定
T的具体类型,和你预期的动态分发(类似C++基类引用)的行为不匹配。 - 额外引入的
BorrowMut完全没有必要,BorrowMut是泛型 trait,调用时编译器无法推断你要转换的目标类型,会进一步加重类型推断的问题。
可行解决方案
提供两种常用实现方案,你可以根据自己的需求选择:
方案1:直接使用trait对象实现动态分发(最符合你的预期)
直接修改do_something的定义,将入参改为trait对象引用,完全走动态分发,和C++传入基类引用的行为一致:
// 修改后的do_something,接收dyn MyTrait的引用,自动走动态分发 fn do_something(obj: &dyn MyTrait) { obj.foo(); } fn main() { let boxed_value = create_object(MyEnum::A); // 对Box解引用后取引用,得到&dyn MyTrait类型直接传入即可 do_something(&*boxed_value); }
运行后会正常输出A。
方案2:给泛型添加?Sized约束,同时支持静态/动态分发
如果你需要保留泛型定义(比如同时要处理已知类型的静态分发场景提升性能),只需要给泛型参数添加?Sized约束,放开编译期固定大小的限制:
// 给T添加?Sized约束,允许T是动态大小的dyn MyTrait fn do_something<T: MyTrait + ?Sized>(obj: &T) { obj.foo(); } fn main() { let boxed_value = create_object(MyEnum::A); // 两种调用方式都可以: // 1. 传入&dyn MyTrait走动态分发 do_something(&*boxed_value); // 2. 直接传入&Box<dyn MyTrait>,此时T被推导为Box<dyn MyTrait>走静态分发 // do_something(&boxed_value); }
这种方案兼容性更强,既可以接收静态类型的引用,也可以接收动态trait对象的引用。
内容的提问来源于stack exchange,提问作者Genus
相关产品推荐
相关产品推荐

