如何在初始化Kotlin对象时存储临时变量?

我正在学习Kotlin,作为学习的一部分,我想设计一个代表一个合理的数字,要求的类:

  • 类应该包含两个不可变的整数字段:分子和分母。
  • 类应该包含有效的equals,hashCode和toString实现。
  • 当分类被初始化时,分子和分母应该被它们的GCD删除(这意味着Ratio(1, 2) == Ratio(2, 4 /* or 4, 8 */) or Ratio(2, 4 /* or 4, 8 */).numerator == 1, .denominator == 2等)
  • 这个类应该包含mul方法,该方法需要另一个Ratio并返回当前比率和给定比例的乘法结果。

我尝试使用适合于这个任务的数据类,但是我无法定义一个自定义的构造函数(分子和分母都需要删除到他们的GCD中)。

可能的方案

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

定义一个类构造函数以便GCD计算一次最简单的方法是什么?

UPDATE

好的,看起来我找到了可能的解决方案:

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

但它表示数据修饰符无用 – 在这个变化之后,Ratio类不再有自动生成的equals / hashCode / toString。

在最新版本的Kotlin – 0.9.66上进行了验证

重现该行为的程序:

 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()) } 

输出:

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

这很清楚,Ratio不再具有自动生成的toString方法

好的,我找到了一个答案(感谢安德烈指出在所描述的用例中必须有私人存储):

 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) } } } 

由于某些原因,如果在类中使用了初始化块,“数据”限定符将会变得毫无用处,所以如果您想要定制构建逻辑并保留自动生成的hashCode / equals / toString方法,则需要使用工厂方法。

怎么样:

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

编辑:公平点关于无用的领域。 另一种方法是使用懒惰评估的属性。 请参阅这里的文档http://kotlinlang.org/docs/reference/delegated-properties.html

这是一个(未经测试)在这..

 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 }