Что такое функция для структур, подобных Java instanceof? - PullRequest
0 голосов
/ 24 августа 2018

Я создаю OOP чат-клиент в Rust. Модуль messages.rs создает и обрабатывает сообщения для других модулей в виде структур: SimpleMessage и ComplexMessage структур:

//! # 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);
    }
}

Меня беспокоит поиск Java-подобной функции, такой как InstanceOf() для структур, которая потенциально могла бы работать следующим образом:

&self.instance_of() -> str

Это будет использоваться для обработки ComplexMessage, отличного от SimpleMessage в графическом интерфейсе, с добавлением кнопки предварительного просмотра и загрузки для ComplexMessage.

Есть идеи?

1 Ответ

0 голосов
/ 24 августа 2018

Прежде всего, если вы попытаетесь портировать идиомы Java OOP на Rust, вам будет трудно.Программисты Rust используют совершенно разные идиомы и шаблоны, которые больше подходят для дизайна языка.

При этом вы можете сравнивать типы, используя std::any::TypeId. функция , аналогичная instanceOf, может быть реализована следующим образом:

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 {}

И использовать ее следующим образом:

let msg = ComplexMessage::new();

println!("msg is ComplexMessage: {}", msg.instance_of::<ComplexMessage>());
println!("msg is SimpleMessage: {}", msg.instance_of::<SimpleMessage>());

Выходы:

msg is ComplexMessage: true
msg is SimpleMessage: false

Обратите внимание, что в Rust нет концепции наследования типов, как в Java, так что это скажет вам, только если это тот же тип.


Более Rusty подход к вашей проблеме,как прокомментировал DK ниже этот ответ, можно было бы использовать enum для моделирования того факта, что у вас есть два вида сообщений.Rust enum s не похожи на Java enum s - они столь же мощны, как struct s, за исключением того, что они моделируют идею альтернатив, в отличие от агрегатов.Вот один из способов, которым вы могли бы реализовать это, используя имеющиеся у вас типы и оборачивая их:

enum Message<'a> {
    Complex(ComplexMessage<'a>),
    Simple(SimpleMessage<'a>),
}

Всякий раз, когда функция может принимать только ComplexMessage, вы можете написать подпись, отражающую это:

fn send_multimedia(msg: ComplexMessage) { ... }

И всякий раз, когда вы можете принять любой тип, используйте 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(),
    }
}
...