To reply to your immediate question, you could add the declaration of an accessor to another trait itself, like this:
trait HasField2 {
fn get_field2(&self) -> u8;
}
and impose this bound on the msg
parameter:
trait Message {
fn send<T: HasField2>(msg: T);
}
finally, call this accessor in impl Message for Red
.
However, this makes a more fundamental problem apparent. You couldn't implement HasField2
for Green
. The underlying issue is that you are expecting different kinds of behavior and "contracts" in both implementations of Message
. In other words, your two implementations of Message
shouldn't probably be impls of the same trait. There's a design issue that only you can resolve using the knowledge of the non-toy-example problem you have in mind.
It also makes little sense to me why the Message
trait has an argument named msg
. Isn't the message self
? And if you are trying to do channel.send(message);
, then are you implementing Message
for a channel, rather than a message? Aren't you indeed confusing self
and the type parameter?
It looks like you are actually trying to write something like a visitor. In that setting you would flip the traits around, and you would have a Channel
trait which can send primitive messages, and then implementations of Message
would rely on Channel
while also being aware of their own, concrete type (and hence, fields). Something like this:
trait Channel {
fn send_bytes(&self, bytes: &[u8]);
}
trait Message {
fn send_to<C: Channel>(&self, channel: &C);
}
impl Message for Red {
fn send_to<C: Channel>(&self, channel: &C) {
let string = format!("Red: {:?}, f2: {}", self, self.f2);
channel.send_bytes(string.as_bytes());
}
}
impl Message for Green {
fn send_to<C: Channel>(&self, channel: &C) {
let string = format!("Green: {:?}", self);
channel.send_bytes(string.as_bytes());
}
}