¿Cómo almacenar variables temporales al inicializar un object Kotlin?

Estoy estudiando Kotlin y como parte de aprenderlo quiero diseñar una class que represente un número racional, requisitos:

  • La class debe contener dos campos integers inmutables: numerador y denominador.
  • La class debe contener implementaciones válidas equals, hashCode y toString.
  • Cuando la class se inicializa, el numerador y el denominador deben eliminarse por su GCD (significa que Ratio(1, 2) == Ratio(2, 4 /* or 4, 8 */) or Ratio(2, 4 /* or 4, 8 */).numerator == 1, .denominator == 2 etc.)
  • Esta class debe contener el método mul que toma otra razón y devuelve el resultado de la multiplicación de la razón actual y la dada.

Traté de usar classs de datos que parecían adecuadas para esa tarea, pero me quedé atrapado con la incapacidad de definir un constructor personalizado (tanto el numerador como el denominador deben eliminarse en su GCD).

Solución posible:

 class Ratio(num : Int, denom : Int) { val numerator = num / gcd(num, denom) val denominator = denom / gcd(num, denom) // GCD calculated twice! } 

¿Cuál es la forma más simple de definir un constructor de class para que GCD se calcule una vez?

ACTUALIZAR

OK, parece que encontré la solución posible:

 data class Ratio(num : Int, denom : Int) { val numerator : Int val denominator : Int { val gcd = calcGcd(num, denom) numerator = num / gcd denominator = denom / gcd } } 

pero hace que el calificador de datos sea inútil; después de este cambio, la class Ratio ya no genera automáticamente / hashCode / toString.

Verificado en la última versión de Kotlin – 0.9.66

Progtwig que reproduce ese comportamiento:

 data class Ratio(num : Int, denom : Int) { val numerator : Int val denominator : Int { val gcd = BigInteger.valueOf(num.toLong()).gcd(BigInteger.valueOf(denom.toLong())).intValue(); numerator = num / gcd; denominator = denom / gcd } } data class Ratio2(val num : Int, val denom : Int) fun main(args: Array<String>) { println("r = " + Ratio(1, 6).toString()) println("r2 = " + Ratio2(1, 6).toString()) } 

salida:

 r = Ratio@4ac68d3e r2 = Ratio2(num=1, denom=6) 

está claro que Ratio ya no se ha generado automáticamente en el método String

OK, encontré una respuesta (gracias a Andrey quien señaló la necesidad de tener un ctor privado en el caso de uso descrito):

 data class Ratio private (val numerator : Int, val denominator : Int) { class object { fun create(numerator : Int, denominator : Int) : Ratio { val gcd = BigInteger.valueOf(numerator.toLong()).gcd(BigInteger.valueOf(denominator.toLong())).intValue(); return Ratio(numerator / gcd, denominator / gcd) } } } 

por alguna razón, el calificador de "datos" se volverá inútil si se usan bloques de initialization en la class, por lo que si desea tener una lógica de construcción personalizada y retener methods autogenerados hashCode / equals / toString, necesitará usar methods de fábrica.

Qué tal si:

 class Ratio(num : Int, denom : Int) { private val theGcd = gcd(num, denom) val numerator = num / theGcd val denominator = denom / theGcd } 

EDIT: punto justo sobre el campo inútil. Una alternativa podría ser usar una propiedad de evaluación diferida. Vea los documentos aquí http://kotlinlang.org/docs/reference/delegated-properties.html

Aquí hay un (no probado) ir a esto …

 import kotlin.properties.Delegates class Ratio(num : Int, denom : Int) { private val theGcd: Int by Delegates.lazy { gcd(num, denom) } val numerator = num / theGcd val denominator = denom / theGcd } 
  • use kotlin para springmvc No se pudo crear una instancia de la class de datos de la class bean
  • java.lang.IncompatibleClassChangeError después de actualizar a kotlin RC1 (1.0.0-rc-1036)
  • Kotlin - lateinit TestRestTemplate no se inicializa para las testings de integración
  • Kotlin: Cómo trabajar con los cambios de Lista: Lanzamiento no seleccionado: kotlin.collections.List <Kotlin.Any?> A kotlin.colletions.List <Waypoint>
  • La inferencia del tipo Kotlin falló
  • Obtener una reference a una function de Kotlin como método Java
  • Agregue datos a Recyclerview en Kotlin Android
  • Inicializar ArrayList <ArrayList <Int >> con un tamaño en kotlin
  • Inflado de disposition incondicional desde el adaptador de vista. kotlin
  • Por qué los numbers que aceptan nulos no son para preservar la identidad
  • Genéricos para RecyclerView.Adapter Android