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

时间:2017-06-07 18:14:16

标签: kotlin

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

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

我试图通过从密封类扩展我的数据类来实现这一目的。

数据类可以扩展密封类,但不是我不确定如何/是否可以接受"超类型所需的参数"密封课。

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

    sealed class Message(val messageId: String)
    
    class Track(val event: String, messageId: String): Message(messageId)
    
  2. 但是,将其更改为数据类并不能编译("数据类主构造函数必须只有属性(val / var)参数。")。

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

    sealed class Message(val messageId: String)
    
    data class Track(val event: String, val messageId: String): Message(messageId)
    
  4. 打开超类型属性并在每个基类中重写它编译得很好:

    sealed class Message(open val messageId: String)
    
    data class Track(val event: String, override val messageId: String): Message(messageId)
    
  5. 理想情况下,我希望接近选项2 - 它允许我结合两个世界中最好的。

    否则,似乎我的选择是使用选项1来处理我自己的数据类功能(copy,hashcode,equals等),或者通过使用选项4打开超类型属性来实现折衷。

1 个答案:

答案 0 :(得分:40)

选项3和4会导致班级持有messageId两次。一旦进入新类,一次进入超类。

解决方案是声明但不在超类中定义变量:

sealed class Message {
    abstract val messageId: String
}

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

这将使{I} Message上的messageId可用,但会将存储委托给实现它的任何内容。