【问题标题】:What is a function for structs like Java's instanceof?像 Java 的 instanceof 这样的结构的函数是什么?
【发布时间】:2018-08-24 13:18:33
【问题描述】:

我正在用 Rust 制作一个 OOP 聊天客户端。模块 messages.rs 以结构体的形式创建和处理其他模块的消息:SimpleMessageComplexMessage 结构体:

//! # 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

这将用于在 GUI 中处理与 SimpleMessage 不同的 ComplexMessage,为 ComplexMessage 添加预览和下载按钮。

有什么想法吗?

【问题讨论】:

  • 鉴于 Rust 的编译时间保证,你为什么需要这个?
  • 请查看如何创建minimal reproducible example,然后查看edit 您的问题以包含它。我们无法判断代码中存在哪些类型、字段等,也无法了解为什么您要实现此目标或哪些代码需要它。尝试在Rust Playground 上重现您的错误,或者您可以在全新的 Cargo 项目中重现它。还有Rust-specific MCVE tips
  • 也许How to match trait implementors 会有所帮助
  • 你知道using instanceof in Java is not a good idea吗?将糟糕的设计从一种语言复制到另一种语言通常不被鼓励。
  • 很难写出第一次的问题——我从你的个人资料中注意到你是一名 CS 学生,所以希望这个不请自来的建议不会不受欢迎:我们的反馈为您提供的绝对不限于 Stack Overflow。它将与您整个职业生涯的每个部分相关。将问题简化为基本要素(“创建 MCVE”)、评估为什么你在做某事、花时间格式化和构建你的沟通等等都是成功的关键(在编程和可能几乎所有东西)。

标签: oop object struct rust instanceof


【解决方案1】:

首先,如果您尝试将 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 那样有类型继承的概念,所以这只会告诉你它是否是完全相同的类型。


正如 DK 在此答案下方评论的那样,解决您的问题的更生锈的方法是使用 enum 来模拟您有两种消息的事实。 Rust enums 与 Java enums 完全不同——它们与 structs 一样强大,只是它们模拟了替代方案的概念,而不是聚合。这是您可以使用您拥有的类型并将它们包装起来的一种方法:

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(),
    }
}

【讨论】:

  • 如果msg 是具有特征类型的引用,并且如果它的值是一些未知的特征实现,SimpleMessageComplexMessage,您使用instance_of 的初始解决方案是否也有效?这就是 Java instanceof 运算符的本质,即测试参数的运行时类型。在您给定的示例中,msg 似乎具有非引用类型ComplexMessage。仅在这种情况下有效的 instanceof 运算符与 Java 中的运算符完全不同,应在答案文本中明确说明。
  • 我也考虑过使用结构元组,虽然没有考虑过枚举,使用它们可能是一个更优雅(并且非常有用)的解决方案,让我试试,谢谢 DK . @Shepmaster
  • Any::is 不是更短的实现吗?
  • @Shepmaster Meh,它将类型限制为Sized。可能不是问题...
  • 感谢@PeterHall 使用枚举它是最优雅/实用的解决方案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多