Rust传递无固定大小动态分发trait作为参数的问题求助
问题根因
你的报错本质是Query trait的方法固定接收&mut dyn Sink<B> trait对象,编译器要将传入的引用自动转换为trait对象时,要求引用指向的类型必须实现Sized trait(编译期大小确定),而你给PushSink的泛型参数S加了?Sized约束,因此无法满足转换要求。
解决方案
方案1:最简适配(无需修改原有Trait定义)
你给S加?Sized属于多余约束,因为即使你要传trait对象,&mut dyn Sink<C>类型本身是胖指针,大小固定(2个usize),本身就实现了Sized trait。直接移除PushSink相关定义中的?Sized约束即可:
// 去掉S的?Sized约束 struct PushSink<'a, B, C, QBC : Query<B, C>, S : Sink<C>> { q_bc : &'a mut QBC, s_c : &'a mut S, _bc : PhantomData<(B, C)> } // 对应Impl也去掉?Sized约束 impl <'a, B, C, QBC: Query<B, C>, S: Sink<C>> PushSink<'a, B, C, QBC, S>{ pub fn new(q_bc: &'a mut QBC, s_c : &'a mut S) -> Self{ PushSink {q_bc : q_bc, s_c : s_c, _bc : PhantomData} } } impl<'a, B, C, QBC: Query<B, C>, S: Sink<C>> Sink<B> for PushSink<'a, B, C, QBC, S>{ fn init(&mut self) { self.q_bc.init(self.s_c); } fn next(&mut self, item: B) { self.q_bc.next(item, self.s_c); } fn end(&mut self) { self.q_bc.end(self.s_c); } }
该方案的优势:
- 完全保留原有
Query、Sinktrait定义不变 - 同时支持传入具体Sized的Sink类型和
&mut dyn Sinktrait对象 - 保留了
Query作为trait对象使用的能力
方案2:性能优化(避免Trait对象开销)
如果不需要把Query作为trait对象使用,可以将Query的方法改为泛型,直接接收任意实现了Sink的类型,无需转换为trait对象,运行时无动态分发开销:
pub trait Query<A,B> { fn init<S: Sink<B> + ?Sized>(&mut self, sink: &mut S); fn next<S: Sink<B> + ?Sized>(&mut self, item: A, sink: &mut S); fn end<S: Sink<B> + ?Sized>(&mut self, sink: &mut S); }
该方案下可以保留PushSink的?Sized约束,编译时会为每个不同的Sink类型生成对应的方法实例,性能更高。
两种方案都完全满足你的要求:基于trait实现、没有使用Box或枚举。
内容的提问来源于stack exchange,提问作者Agnishom Chattopadhyay
相关产品推荐
相关产品推荐

