如何避免在此结构定义中使用 PhantomData?
How can I avoid PhantomData in this struct definition?
我有一个看起来像这样的特征:
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
的实例。这太丑了。例如,我必须手动提供正确的 Sync/Send 特征实现:
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 {}
auto trait 实现会有一个额外的 where C: Send/Sync
限制,这在此处不合适。
是否有 PhantomData 的替代方案允许我对 FirstHandler<C>
和 C
之间的关系进行编码,以便 Rust 编译器满意并且我不需要更多 unsafe
代码?
我不是在寻找关联类型。处理程序特征及其实现程序在库中定义,C
的具体类型在应用程序使用库,因此具体类型 C
不能由处理程序的特征实现定义。
这个设计的想法是允许处理程序链累积处理程序链中所需的 C
的所有特征边界,这样当我将 handler
变量作为在第二个片段中显示,那么隐含的特征界限是 C: ConnectionThatWorksWithFirstHandler + ConnectionThatWorksWithSecondHandler + ConnectionThatWorksWithFinalHandler
.
无需在结构定义时对内部处理程序强制执行约束。您可以延迟它们,直到为 FirstHandler
.
实现 Handler
特征
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) {
//...
}
}
我有一个看起来像这样的特征:
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
的实例。这太丑了。例如,我必须手动提供正确的 Sync/Send 特征实现:
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 {}
auto trait 实现会有一个额外的 where C: Send/Sync
限制,这在此处不合适。
是否有 PhantomData 的替代方案允许我对 FirstHandler<C>
和 C
之间的关系进行编码,以便 Rust 编译器满意并且我不需要更多 unsafe
代码?
我不是在寻找关联类型。处理程序特征及其实现程序在库中定义,C
的具体类型在应用程序使用库,因此具体类型 C
不能由处理程序的特征实现定义。
这个设计的想法是允许处理程序链累积处理程序链中所需的 C
的所有特征边界,这样当我将 handler
变量作为在第二个片段中显示,那么隐含的特征界限是 C: ConnectionThatWorksWithFirstHandler + ConnectionThatWorksWithSecondHandler + ConnectionThatWorksWithFinalHandler
.
无需在结构定义时对内部处理程序强制执行约束。您可以延迟它们,直到为 FirstHandler
.
Handler
特征
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) {
//...
}
}