从 Kotlin 中的密封 class 扩展数据 class

Extending data class from a sealed class in Kotlin

我有一组共享一些公共字段的数据 classes,所以理想情况下,我想在超类型(本例中为 Message)中声明这些数据,并能够编写操作函数如果他们需要访问这些公共字段(本例中的 messageId),则在超类型上。

fun operate(m: Message) {
  use(m.messageId)
}

我试图通过从密封的 class.

扩展我的数据 classes 来实现这一点

Data classes 可以扩展 sealed classes,但我不确定 how/if 它们是否可以接受 "supertype" sealed [=51] 所需的参数=].

  1. 从密封的 class 扩展常规 class 编译就好了。

    sealed class Message(val messageId: String)
    
    class Track(val event: String, messageId: String): Message(messageId)
    
  2. 但是,将其更改为数据 class 不会编译 ("Data class primary constructor must have only property (val/var) parameters.")。

    sealed class Message(val messageId: String)
    
    data class Track(val event: String, messageId: String): Message(messageId)
    
  3. 将参数声明为 属性 也不会编译('messageId' 隐藏超类型 'Message' 的成员并且需要 'override' 修饰符' ").

    sealed class Message(val messageId: String)
    
    data class Track(val event: String, val messageId: String): Message(messageId)
    
  4. 打开超类型 属性 并在每个基础 classes 中覆盖它编译正常:

    sealed class Message(open val messageId: String)
    
    data class Track(val event: String, override val messageId: String): Message(messageId)
    

理想情况下,我想要接近选项 2 的东西 - 它允许我结合两个世界的优点。

否则,我的选择似乎是使用选项 1 手动处理我自己的数据 class 功能(复制、哈希码、等号等),或者通过使用选项 4 打开超类型属性来妥协.

选项 3 和 4 将导致 class 持有 messageId 两次。一次在新 class 一次在它的超级 class.

解决办法是在superclass中声明而不定义变量class:

sealed class Message {
    abstract val messageId: String
}

data class Track(val event: String, override val messageId: String): Message()

这将使 messageId 在 Message 上可用,但将存储委托给实现它的任何对象。