首页 > 解决方案 > 隐藏两个特征共享的关联类型

问题描述

我具有特定消息类型的发送者和接收者的特征。

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

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

我希望能够使用run()传递消息的方法将一对兼容的发送方和接收方存储在一个结构中,即receiver.receive(sender.send()).

我的直觉是这个run()方法不需要知道消息类型(因为所有出现的消息类型都是在内部处理的),所以结构和它的方法不应该暴露消息类型。我认为当您拥有更大的发送方-接收方网络时,跟踪消息类型也变得不切实际。

做这个的最好方式是什么?我试过了Any这主要是有效的。然而,

这是我到目前为止所得到的:

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());
    }
}

标签: rusttraitsassociated-types

解决方案


您应该在此处创建将Sendsand绑定Receives在一起的类型SendAndReceiveInner。然后使用 trait 对象,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();
    }
}

这涉及的拳击要少得多,但仍然有点样板。您可以只在Box<dyn ...>表单中使用它,因为此时最外面SendAndReceive的功能并不多,但封装和 API 表示取决于读者。


推荐阅读