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

f2p*_*eek 33 kotlin

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

fun operate(m: Message) {
  use(m.messageId)
}
Run Code Online (Sandbox Code Playgroud)

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

数据类可以扩展密封类,但不是我不确定它们是否可以接受"超类型"密封类所需的参数.

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

    sealed class Message(val messageId: String)
    
    class Track(val event: String, messageId: String): Message(messageId)
    
    Run Code Online (Sandbox Code Playgroud)
  2. 但是,将其更改为数据类不会编译("Data class主构造函数必须只有property(val/var)参数.").

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

    sealed class Message(val messageId: String)
    
    data class Track(val event: String, val messageId: String): Message(messageId)
    
    Run Code Online (Sandbox Code Playgroud)
  4. 打开supertype属性并在每个基类中重写它可以很好地编译:

    sealed class Message(open val messageId: String)
    
    data class Track(val event: String, override val messageId: String): Message(messageId)
    
    Run Code Online (Sandbox Code Playgroud)

理想情况下,我希望接近选项2 - 它允许我结合两个世界的最佳.

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

Kis*_*kae 48

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

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

sealed class Message {
    abstract val messageId: String
}

data class Track(val event: String, override val messageId: String): Message()
Run Code Online (Sandbox Code Playgroud)

这将使messageId可用Message,但将存储委托给实现它的任何内容.