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

Ale*_*lex 5 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!
}
Run Code Online (Sandbox Code Playgroud)

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

更新

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

data class Ratio(num : Int, denom : Int) {
  val numerator : Int
  val denominator : Int

  {
    val gcd = calcGcd(num, denom)
    numerator = num / gcd
    denominator = denom / gcd
  }
}
Run Code Online (Sandbox Code Playgroud)

但它使数据限定符无用 - 在此更改之后,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())
}
Run Code Online (Sandbox Code Playgroud)

输出:

r = Ratio@4ac68d3e
r2 = Ratio2(num=1, denom=6)
Run Code Online (Sandbox Code Playgroud)

很明显 Ratio 不再有自动生成的 toString 方法

Ale*_*lex 3

好的,我找到了一个答案(感谢 Andrey,他指出在所描述的用例中需要有私人角色):

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)
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

由于某种原因,如果在类中使用初始化块,“data”限定符将变得无用,因此,如果您想要自定义构造逻辑并保留自动生成的 hashCode/equals/toString 方法,您将需要使用工厂方法。