简体   繁体   English

隐藏两个特征共享的关联类型

[英]Hiding associated type shared by two traits

I have traits for senders and receivers of a specific message type.我具有特定消息类型的发送者和接收者的特征。

pub trait Sends {
    type Message;
    fn send(&self) -> Self::Message;
}

pub trait Receives {
    type Message;
    fn receive(&mut self, msg: Self::Message);
}

I want to be able to store a compatible pair of sender and receiver in a struct with a run() method that passes messages, ie receiver.receive(sender.send()) .我希望能够使用传递消息的run()方法将一对兼容的发送方和接收方存储在一个结构中,即receiver.receive(sender.send())

My intuition is that this run() method should not require knowledge of the message type (because all occurrences of the message type are handled internally), so the struct and its method should not expose the message type.我的直觉是这个run()方法不应该要求知道消息类型(因为所有出现的消息类型都是在内部处理的),所以结构和它的方法不应该暴露消息类型。 I think keeping track of the message types also becomes impractical when you have a bigger sender-receiver network.我认为当您拥有更大的发送方-接收方网络时,跟踪消息类型也变得不切实际。

What is the best way to do this?做这个的最好方式是什么? I tried it out with Any , which mostly works.我用Any 进行了尝试,这主要是有效的。 However,然而,

  • I'm having difficulty actually creating a SendAny from a Send , and same for the receiver.我实际上很难从Send创建一个SendAny ,对于接收者也是如此。
  • I hope there is a more elegant and efficient way, since this introduces boilerplate and needless boxing/unboxing.我希望有一种更优雅和有效的方式,因为这引入了样板和不必要的装箱/拆箱。

Here is what I've got so far:这是我到目前为止所得到的:

trait SendsAny {
    fn send_any(&self) -> Box<dyn Any>;
}

impl<T> SendsAny for T
where
    T: Sends,
    T::Message: 'static,
{
    fn send_any(&self) -> Box<dyn Any> {
        Box::new(self.send())
    }
}

// Similar for ReceivesAny

struct SendAndReceive {
    // These have to have matching Message types
    tx: Box<dyn SendsAny>,
    rx: Box<dyn ReceivesAny>,
}

impl SendAndReceive {
    fn new<M: 'static>(
        tx: Box<dyn Sends<Message = M>>,
        rx: Box<dyn Receives<Message = M>>,
    ) -> Self {
        // This doesn't work
        let tx = tx as Box<dyn SendsAny>;
        todo!()
    }

    fn run(&mut self) {
        self.rx.receive_any(self.tx.send_any());
    }
}

You should make the type that binds the Sends and Receives together, here SendAndReceiveInner .您应该创建将SendsReceives绑定在一起的类型,这里SendAndReceiveInner And then use a trait object, Box<dyn SendAndReceiveAny> to use it in the type-erased form in SendAndReceive .然后使用特征 object, Box<dyn SendAndReceiveAny>SendAndReceive中以类型擦除形式使用它。

struct SendAndReceiveInner<R, S>
where
    S: Sends,
    R: Receives<Message = S::Message>,
{
    tx: S,
    rx: R,
}

trait SendAndReceiveAny {
    fn run(&mut self);
}

impl<R, S> SendAndReceiveAny for SendAndReceiveInner<R, S>
where
    S: Sends,
    R: Receives<Message = S::Message>,
{
    fn run(&mut self) {
        self.rx.receive(self.tx.send());
    }
}

struct SendAndReceive {
    inner: Box<dyn SendAndReceiveAny>,
}

impl SendAndReceive {
    fn new<R, S>(tx: S, rx: R) -> Self
    where
        S: Sends + 'static,
        R: Receives<Message = S::Message> + 'static,
    {
        Self {
            inner: Box::new(SendAndReceiveInner{ tx, rx }),
        }
    }

    fn run(&mut self) {
        self.inner.run();
    }
}

This has a lot less boxing involved but still a bit of boilerplate.这涉及的拳击要少得多,但仍然有点样板。 You could just use it in the Box<dyn...> form since the outermost SendAndReceive isn't doing much at this point, but encapsulation and API presentation is up to the reader.您可以只在Box<dyn...>表单中使用它,因为此时最外面的SendAndReceive并没有做太多事情,但封装和 API 演示文稿取决于读者。

I don't quite know if this is what you are looking for, but you could make the SendAndReceive generic on the sender and receiver:我不太清楚这是否是您正在寻找的,但您可以在发送者和接收者上使SendAndReceive通用:

pub trait Sends {
    type Message;
    fn send(&self) -> Self::Message;
}

pub trait Receives {
    type Message;
    fn receive(&mut self, msg: Self::Message);
}

struct SendAndReceive<R,S> 
    where S: Sends, R: Receives<Message=S::Message>
{
    // These have to have matching Message types
    tx: S,
    rx: R,
}

impl<R,S> SendAndReceive<R,S> 
    where S: Sends, R: Receives<Message=S::Message>
{
    fn new(tx: S,rx: R,) -> Self {
        Self{tx, rx}
    }

    fn run(&mut self) {
        self.rx.receive(self.tx.send());
    }
}

The struct is therefore agnostic to the type of the message but generic on the sender/receiver.因此,该结构与消息的类型无关,但在发送方/接收方上是通用的。 Also avoid the whole Any machinery.还要避免Any

You could also go the other way and make the struct generic on the message:您也可以 go 以另一种方式使结构在消息上通用:

pub trait Sends {
    type Message;
    fn send(&self) -> Self::Message;
}

pub trait Receives {
    type Message;
    fn receive(&mut self, msg: Self::Message);
}

struct SendAndReceive<M> {
    // These have to have matching Message types
    tx: Box<dyn Sends<Message=M>>,
    rx: Box<dyn Receives<Message=M>>,
}

impl<M> SendAndReceive<M> {
    fn new(
        tx: Box<dyn Sends<Message = M>>,
        rx: Box<dyn Receives<Message = M>>,
    ) -> Self {
        Self{tx,rx}
    }

    fn run(&mut self) {
        self.rx.receive(self.tx.send());
    }
}

This again avoids Any and doesn't need to be generic on the sender/receiver but must be generic on the message type.这再次避免了Any并且不需要在发送方/接收方上是通用的,但在消息类型上必须是通用的。

I don't know whether these two are what you are looking for, but I don't see any other way to avoid run needing specific types/traits.我不知道这两个是否是您正在寻找的,但我没有看到任何其他方法可以避免run需要特定类型/特征。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM