I have the 2 following traits:
trait Filter {
type Message;
fn is_valid(&self, message: &Self::Message) -> bool;
}
trait Client {
type Message;
fn send(&self, message: &Self::Message) -> Result<(), Error>;
}
I would like an implementation of Filter and Client to use the same Message type.
struct ClientWithFilter<C: Client, F: Filter> {
filter: F,
client: C,
}
impl<C: Client, F: Filter> ClientWithFilter<C, F> {
/// C::Message or F::Message???
fn check_and_send(&self, message: &C::Message) -> Result<(), Error> {
if self.filter.is_valid(message) {
self.client.send(message)
} else {
Err(Error::MessageInvalid)
}
}
}
This does not compile:
if self.filter.is_valid(message) {
| ^^^^^^^ expected client::Filter::Message, found client::Client::Message
|
= note: expected type `&<F as client::Filter>::Message`
found type `&<C as client::Client>::Message`
The compiler sees 2 distinct types where I would like to have a single one. How can I write this in Rust in a correct way?
You need to constrain the type parameters appropriately:
struct ClientWithFilter<C, F>
where
C: Client,
F: Filter<Message = C::Message>,
{
filter: F,
client: C,
}
impl<C, F> ClientWithFilter<C, F>
where
C: Client,
F: Filter<Message = C::Message>,
{
fn check_and_send(&self, message: &C::Message) -> Result<(), Error> {
if self.filter.is_valid(message) {
self.client.send(message)
} else {
Err(Error::MessageInvalid)
}
}
}
playground
The redundant duplication of the constraints on the impl is necessary for now, I think. I believe there's an RFC to let impls inherit constraints from the struct definition.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With