我正在学习Kotlin,作为学习它的一部分,我想设计一个代表理性数字,要求的课程:
Ratio(1, 2) == Ratio(2, 4 /* or 4, 8 */) or Ratio(2, 4 /* or 4, 8 */).numerator == 1, .denominator == 2
等。)我尝试使用看起来适合该任务的数据类,但我无法定义自定义构造函数(分子和分母都需要删除到他们的GCD中)。
可能的解决方案:
class Ratio(num : Int, denom : Int) {
val numerator = num / gcd(num, denom)
val denominator = denom / gcd(num, denom) // GCD calculated twice!
}
定义类构造函数以便计算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
}
}
但它使数据限定符无效 - 在此更改之后,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方法
答案 0 :(得分:3)
好的,我找到了答案(感谢安德烈指出在描述的用例中需要私人ctor):
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)
}
}
}
由于某种原因,如果在类中使用初始化程序块,'data'限定符将变得无用,因此如果您想要自定义构造逻辑并保留自动生成的hashCode / equals / toString方法,则需要使用工厂方法
答案 1 :(得分:0)
怎么样:
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
}