descargar - Propiedad incluida/excluida en las clases de datos de Kotlin
kotlin vs scala (5)
Supongamos que solo quiero que se incluyan uno o dos campos en las implementaciones equals y hashCode generadas (o tal vez excluya uno o más campos). Para una clase simple, por ejemplo:
data class Person(val id: String, val name: String)
Groovy tiene esto:
@EqualsAndHashCode(includes = ''id'')
Lombok tiene esto:
@EqualsAndHashCode(of = "id")
¿Cuál es la forma idiomática de hacer esto en Kotlin?
Mi enfoque hasta ahora
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
}
}
Sin embargo, me siento mal ... Realmente no quiero que el name
sea mutable, y la definición adicional del constructor es fea.
Aquí hay un enfoque algo creativo:
data class IncludedArgs(val args: Array<out Any>)
fun includedArgs(vararg args: Any) = IncludedArgs(args)
abstract class Base {
abstract val included : IncludedArgs
override fun equals(other: Any?) = when {
this identityEquals other -> true
other is Base -> included == other.included
else -> false
}
override fun hashCode() = included.hashCode()
override fun toString() = included.toString()
}
class Foo(val a: String, val b : String) : Base() {
override val included = includedArgs(a)
}
fun main(args : Array<String>) {
val foo1 = Foo("a", "b")
val foo2 = Foo("a", "B")
println(foo1 == foo2) //prints "true"
println(foo1) //prints "IncludedArgs(args=[a])"
}
Desafortunadamente, esta solución ya no funciona y no tengo (aún) otra buena idea para esta pregunta.
Las funciones generadas automáticamente utilizan solo las propiedades (parámetros con val
o var
) declaradas en el constructor primario. Así que puedes escribir:
data class Person(val id: String, name: String) {
val name: String = name
}
De más información ver referencia sobre clases de datos .
Esto se basa en el enfoque de @ bashor y utiliza un constructor primario privado y un constructor secundario público. Lamentablemente, la propiedad que se debe ignorar para iguales no puede ser un val, pero se puede ocultar el configurador, por lo que el resultado es equivalente desde una perspectiva externa.
data class ExampleDataClass private constructor(val important: String) {
var notSoImportant: String = ""
private set
constructor(important: String, notSoImportant: String) : this(important) {
this.notSoImportant = notSoImportant
}
}
He utilizado este enfoque.
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)
}
Tampoco sé "la forma idomática" en Kotlin (1.1) para hacer esto ...
Terminé sobrescribiendo equals
y hashCode
:
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()
}
}
¿No hay una manera "mejor"?