What is a function for structs like Java's instanceof?

寵の児 提交于 2020-12-08 20:05:04

问题


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 enums are nothing like Java enums - they are just as powerful as structs 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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!