Cómo hacer un generador para una class de datos de Kotlin con muchas properties inmutables

Tengo una class de datos Kotlin que estoy construyendo con muchas properties inmutables, que se obtienen de consultas SQL separadas. Si quiero build la class de datos usando el patrón del generador, ¿cómo hago esto sin hacer esas properties mutables?

Por ejemplo, en lugar de build a través de

var data = MyData(val1, val2, val3) 

Quiero usar

 builder.someVal(val1) // compute val2 builder.someOtherVal(val2) // ... var data = builder.build() 

mientras se sigue utilizando la característica de class de datos de Kotlin y las properties inmutables.

    No creo que Kotlin tenga constructores nativos. Siempre puede calcular todos los valores y crear el object al final.

    Si aún desea usar un generador, deberá implementarlo usted mismo. Verifique esta pregunta

    Estoy de acuerdo con el bloque de copy de datos en la respuesta de Grzegorz, pero es esencialmente la misma syntax que crear classs de datos con constructores. Si quieres usar ese método y mantener todo legible, probablemente estarás computando todo de antemano y pasando todos los valores al final.

    Para tener algo más como un constructor, puede considerar lo siguiente:

    Digamos que su class de datos es

     data class Data(val text: String, val number: Int, val time: Long) 

    Puede crear una versión del constructor mutable como tal, con un método de compilation para crear la class de datos:

     class Builder { var text = "hello" var number = 2 var time = System.currentTimeMillis() internal fun build() = Data(text, number, time) } 

    Junto con un método de construcción como ese:

     fun createData(action: Builder.() -> Unit): Data { val builder = Builder() builder.action() return builder.build() } 

    La acción es una function desde la que puede modificar los valores directamente, y createData convertirá en una class de datos directamente después. De esta forma, puedes crear una class de datos con:

     val data: Data = createData { //execute stuff here text = "new text" //calculate number number = -1 //calculate time time = 222L } 

    No hay methods setter por ejemplo, pero puede asignar directamente las variables mutables con sus nuevos valores y llamar a otros methods dentro del generador.

    También puede hacer uso de get y set de kotlin especificando sus propias funciones para cada variable para que pueda hacer algo más que establecer el campo.

    Tampoco es necesario devolver la class de generador actual, ya que siempre tiene acceso a sus variables.

    Nota adicional: si te importa, createData se puede acortar a esto:

     fun createData(action: Builder.() -> Unit): Data = with(Builder()) { action(); build() }. 

    "Con un nuevo desarrollador, aplique nuestra acción y compilation"

    No es necesario crear constructores personalizados en Kotlin: para lograr una semántica similar a un constructor, puede aprovechar el método de copy ; es perfecto para situaciones en las que desea get copys de objects con pequeñas modificaciones.

     data class MyData(val val1: String? = null, val val2: String? = null, val val3: String? = null) val temp = MyData() .copy(val1 = "1") .copy(val2 = "2") .copy(val3 = "3") 

    O:

     val empty = MyData() val with1 = empty.copy(val1 = "1") val with2 = with1.copy(val2 = "2") val with3 = with2.copy(val3 = "3") 

    Como quiere que todo sea inmutable, la copy debe suceder en todas las etapas.

    Además, está bien tener properties mutables en el generador siempre que el resultado producido por él sea inmutable.

    Es posible mecanizar la creación de las classs de comstackdor con procesadores de anotación. Acabo de crear ephemient / builder-generator para demostrar esto.

    Tenga en count que actualmente, kapt funciona bien para código Java generado, pero hay algunos problemas con el código Kotlin generado (vea KT-14070 ). Para estos fines, esto no es un problema, siempre que las annotations de anulabilidad se copien de las classs originales de Kotlin a los constructores Java generados (para que el código de Kotlin que utiliza el código Java generado vea types nullable / no nulable en lugar de solo plataforma types).