属性包括/排除Kotlin数据类

jks*_*der 27 kotlin

假设我只想在生成的equals和hashCode实现中包含一个或两个字段(或者可能排除一个或多个字段).对于一个简单的类,例如:

data class Person(val id: String, val name: String)
Run Code Online (Sandbox Code Playgroud)

Groovy有这个:

@EqualsAndHashCode(includes = 'id')
Run Code Online (Sandbox Code Playgroud)

龙目岛有这个:

@EqualsAndHashCode(of = "id")
Run Code Online (Sandbox Code Playgroud)

在Kotlin这样做的惯用方法是什么?

到目前为止我的方法

data class Person(val id: String) {
   // at least we can guarantee it is present at access time
   var name: String by Delegates.notNull()

   constructor(id: String, name: String): this(id) {
      this.name = name
   }
}
Run Code Online (Sandbox Code Playgroud)

虽然感觉不对......我真的不想name变成可变的,额外的构造函数定义很难看.

Dun*_*gor 12

我用过这种方法.

data class Person(val id: String, val name: String) {
   override fun equals(other: Person) = EssentialData(this) == EssentialData(other)
   override fun hashCode() = EssentialData(this).hashCode()
   override fun toString() = EssentialData(this).toString().replaceFirst("EssentialData", "Person")
}

private data class EssentialData(val id: String) {
   constructor(person: Person) : this(id = person.id) 
}
Run Code Online (Sandbox Code Playgroud)

  • 这看起来有点麻烦。这仍然是迄今为止最好的解决方案吗? (3认同)
  • 改进 ```equals``` fun : ```override fun equals(other: Any?):Boolean{ if(other != Person) return false return EssentialData(this) == EssentialData(other) } `` ` (3认同)

Nil*_*mat 11

这建立在 @bashor 的方法之上,并使用私有主构造函数和公共辅助构造函数。遗憾的是,equals 要忽略的属性不能是 val,但可以隐藏 setter,因此从外部角度来看结果是等效的。

data class ExampleDataClass private constructor(val important: String) {
  var notSoImportant: String = ""
    private set

  constructor(important: String, notSoImportant: String) : this(important) {
    this.notSoImportant = notSoImportant
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 我相信这是目前推荐的方法。https://kotlinlang.org/docs/data-classes.html#properties-declared-in-the-class-body (2认同)

bas*_*hor 9

不幸的是,这个解决方案不再有效,而且我还没有(这个)这个问题的另一个好主意.


自动生成的函数仅使用在主构造函数中声明的属性(带val或的参数var).所以你可以写:

data class Person(val id: String, name: String) {
   val name: String = name
}
Run Code Online (Sandbox Code Playgroud)

有关更多信息,请参阅有关数据类的参考.

  • 数据类不再(Kotlin 1.0 beta)允许在构造函数之外声明的任何属性,此解决方案无效. (23认同)

Far*_*tab 7

这种方法可能适用于财产排除:

class SkipProperty<T>(val property: T) {
  override fun equals(other: Any?) = true
  override fun hashCode() = 0
}
Run Code Online (Sandbox Code Playgroud)

SkipProperty.equals简单地返回true,这会导致嵌入property被跳过equals父对象。

data class Person(
    val id: String, 
    val name: SkipProperty<String>
)
Run Code Online (Sandbox Code Playgroud)


Pet*_*eti 5

我也不知道Kotlin(1.1)中的“惯性方式”会执行此操作...

我结束了覆盖equalshashCode

data class Person(val id: String,
                  val name: String) {

    override fun equals(other: Any?): Boolean {
        if (this === other) return true
        if (other?.javaClass != javaClass) return false

        other as Person

        if (id != other.id) return false

        return true
    }

    override fun hashCode(): Int {
        return id.hashCode()
    }
}
Run Code Online (Sandbox Code Playgroud)

有没有“更好”的方式?