You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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、Sink trait定义不变
  • 同时支持传入具体Sized的Sink类型和&mut dyn Sink trait对象
  • 保留了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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.18 23:15:03