如何避免在此结构定义中使用PhantomData?

时间:2018-09-05 14:54:03

标签: rust traits

我的特质看起来像这样:

trait Handler<C> {
    fn handle(&self, msg: &Message, connection: &mut C);
}

实例应该被链接起来,就像您为HTTP处理程序链接中间件一样:

let handler = FirstHandler {
     next: SecondHandler {
         next: FinalHandler {},
     },
};

每种处理程序类型都可以对类型C施加其他约束:

trait ConnectionThatWorksWithFirstHandler {
    ...
}

struct FirstHandler<C: ConnectionThatWorksWithFirstHandler, H: Handler<C>> {
    next: H,
    _phantom: PhantomData<C>,
}

如您在此处看到的,我需要一个PhantomData<C>来避免错误E0392(parameter C is never used)。但是,PhantomData在语义上是错误的,因为处理程序未保存C的实例。这很丑。例如,我必须手动提供正确的“同步/发送”特征实现:

unsafe impl<C: ConnectionThatWorksWithFirstHandler, H: Handler<C>> Send for Handler<C, H> where H: Send {}
unsafe impl<C: ConnectionThatWorksWithFirstHandler, H: Handler<C>> Sync for Handler<C, H> where H: Sync {}

自动特征实现将有一个附加的where C: Send/Sync边界,此处不合适。

是否有PhantomData的替代方法,可以让我对FirstHandler<C>C之间的关系进行编码,以使Rust编译器很高兴并且不需要更多的unsafe代码? / p>

我不在寻找关联的类型。处理程序特征及其实现程序在库中定义,C的具体类型在使用该库的应用程序中定义,因此,具体类型C不能由处理程序的特征实现定义。

这种设计的想法是允许处理程序链累积处理程序链中所需的C的所有特征范围,以便当我有handler变量时,如下所示第二个代码段,则隐含的特征范围为C: ConnectionThatWorksWithFirstHandler + ConnectionThatWorksWithSecondHandler + ConnectionThatWorksWithFinalHandler

1 个答案:

答案 0 :(得分:7)

无需在结构定义时对内部处理程序强制执行约束。您可以延迟它们,直到为Handler实现FirstHandler特质为止。

trait Handler<C> {
    fn handle(&self, msg: &Message, connection: &mut C);
}

struct FirstHandler<H> {
    next: H
}

impl<C, H> Handler<C> for FirstHandler<H>
where
    H: Handler<C>,
    C: ConnectionThatWorksWithFirstHandler,
{
    fn handle(&self, msg: &Message, connection: &mut C) {
        //...
    }
}