简体   繁体   English

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

[英]Extending data class from a sealed class in Kotlin

I have a set of data classes that share some common fields, So ideally I'd like to declare those in a supertype (Message in this example), and be able to write functions that operate on the supertype if they need access to these common fields (messageId in this example).我有一组共享一些公共字段的数据类,因此理想情况下,我想在超类型(本示例中为 Message)中声明它们,并且如果需要访问这些公共字段,则能够编写对超类型进行操作的函数字段(本例中的 messageId)。

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

I tried to accomplish this by extending my data classes from a sealed class.我试图通过从密封类扩展我的数据类来实现这一点。

Data classes may extend sealed classes, but not I'm not sure how/if they can accept arguments required by the "supertype" sealed class.数据类可以扩展密封类,但我不确定它们如何/是否可以接受“超类型”密封类所需的参数。

  1. Extending a regular class from a sealed class compiles just fine.从密封类扩展常规类编译就好了。

     sealed class Message(val messageId: String) class Track(val event: String, messageId: String): Message(messageId)
  2. However, changing it to a data class doesn't compile ("Data class primary constructor must have only property (val/var) parameters.").但是,将其更改为数据类不会编译(“数据类主构造函数必须只有属性(val/var)参数。”)。

     sealed class Message(val messageId: String) data class Track(val event: String, messageId: String): Message(messageId)
  3. Declaring the parameter as a property also doesn't compile ("'messageId' hides member of supertype 'Message' and needs 'override' modifier'").将参数声明为属性也不会编译(“'messageId' 隐藏了超类型 'Message' 的成员并且需要 'override' 修饰符'”)。

     sealed class Message(val messageId: String) data class Track(val event: String, val messageId: String): Message(messageId)
  4. Opening the supertype property and overriding it in each of the base classes compiles fine:打开超类型属性并在每个基类中覆盖它可以很好地编译:

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

Ideally I would like something close to Option 2 - it allows me to combine the best of both worlds.理想情况下,我想要接近选项 2 的东西——它让我能够结合两全其美。

Otherwise, it seems my options are either handrolling my own data class functionality (copy, hashcode, equals etc) with option 1, or live with a compromise by opening up up the supertype properties with option 4.否则,我的选择似乎是使用选项 1 手动滚动我自己的数据类功能(复制、哈希码、等于等),或者通过使用选项 4 打开超类型属性来妥协。

Options 3 and 4 would result in the class holding messageId twice.选项 3 和 4 将导致该类持有两次messageId Once in the new class and once in its superclass.一次在新类中,一次在其超类中。

The solution is to declare but not define the variable in the superclass:解决方法是在超类中声明但不定义变量:

sealed class Message {
    abstract val messageId: String
}

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

This will make the messageId available on Message , but delegates the storage to whatever implements it.这将使 messageId 在Message可用,但将存储委托给任何实现它的人。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM