Скрытие связанного типа, общего для двух трейтов

У меня есть черты для отправителей и получателей определенного типа сообщения.

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, который в основном работает. Однако,

  • У меня возникли трудности с созданием SendAny из Send, и то же самое для приемника.
  • Я надеюсь, что есть более элегантный и эффективный способ, так как он вводит шаблон и ненужную упаковку/распаковку.

Вот что у меня есть до сих пор:

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

person nnnmmm    schedule 05.04.2021    source источник


Ответы (2)


Вы должны сделать тип, который связывает Sends и Receives вместе, здесь SendAndReceiveInner. А затем используйте трейт-объект 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 остаются на усмотрение читателя.

person kmdreko    schedule 06.04.2021

Я не совсем уверен, что это то, что вы ищете, но вы можете сделать общий 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());
    }
}

Таким образом, структура не зависит от типа сообщения, но является универсальной для отправителя/получателя. Также избегайте всей Any техники.

Вы также можете пойти другим путем и сделать структуру общей для сообщения:

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

Это снова позволяет избежать Any и не обязательно должно быть универсальным для отправителя/получателя, но должно быть универсальным для типа сообщения.

Я не знаю, являются ли эти двое тем, что вы ищете, но я не вижу другого способа избежать run необходимости определенных типов/черт.

person Emoun    schedule 05.04.2021
comment
Спасибо, но я ищу решение, в котором SendAndReceive не имеет параметров типа. - person nnnmmm; 05.04.2021