问题
I'm making an OOP chat client in Rust. The module messages.rs creates and handles messages to other modules as structs: SimpleMessage
and ComplexMessage
structs:
//! # Messages
use time::SteadyTime;
/// Represents a simple text message
pub struct SimpleMessage<'a> {
pub user: ...
pub time: &'a SteadyTime<'a>,
pub content: &'a str,
}
/// Represents attachments, like text or multimedia files.
pub struct ComplexMessage<'a> {
pub user: ...
pub time: &'a SteadyTime<'a>,
//pub content: PENDING
}
impl<'a> SimpleMessage<'a> { }
impl<'a> ComplexMessage<'a> { }
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn is_simple() {
assert_eq!(&self.instance_of(), SimpleMessage);
}
#[test]
fn is_complex() {
assert_eq!(&self.instance_of(), ComplexMessage);
}
}
I'm troubled finding a Java-like function such as InstanceOf()
for structs, that would potentially work like:
&self.instance_of() -> str
This would be used to process a ComplexMessage
different from a SimpleMessage
in a GUI, adding a preview and download button for the ComplexMessage
.
Any ideas?
回答1:
First of all, if you try to port Java OOP idioms to Rust you are going to have a hard time. Rust programmers use completely different idioms and patterns, which are more suited to the design of the language.
That said, you can compare types using std::any::TypeId
. A similar function to instanceOf
can be implemented like this:
use std::any::{Any, TypeId};
trait InstanceOf
where
Self: Any,
{
fn instance_of<U: ?Sized + Any>(&self) -> bool {
TypeId::of::<Self>() == TypeId::of::<U>()
}
}
// implement this trait for every type that implements `Any` (which is most types)
impl<T: ?Sized + Any> InstanceOf for T {}
And use it like this:
let msg = ComplexMessage::new();
println!("msg is ComplexMessage: {}", msg.instance_of::<ComplexMessage>());
println!("msg is SimpleMessage: {}", msg.instance_of::<SimpleMessage>());
Outputs:
msg is ComplexMessage: true
msg is SimpleMessage: false
Note that Rust does not have a concept of type inheritance like Java does, so this will only tell you if it is exactly the same type.
A more Rusty approach to your problem, as DK commented below this answer, would be to use an enum
to model the fact that you have two kinds of message. Rust enum
s are nothing like Java enum
s - they are just as powerful as struct
s except they model the idea of alternatives, as opposed to aggregates. Here is one way you could implement this using the types you have and wrapping them up:
enum Message<'a> {
Complex(ComplexMessage<'a>),
Simple(SimpleMessage<'a>),
}
Whenever a function can only accept a ComplexMessage
you can write the signature to reflect that:
fn send_multimedia(msg: ComplexMessage) { ... }
And whenever you can accept either type, use the enum
:
fn get_msg_size(msg: Message) -> usize {
match(msg) {
Message::Complex(complex) => complex.content.len() + complex.file.size(),
Message::Simple(simple) => simple.content.len(),
}
}
来源:https://stackoverflow.com/questions/52005382/what-is-a-function-for-structs-like-javas-instanceof