操作员超载Kotlin

问题描述 投票:0回答:3

我不是Kotlin的新手,我正在为我定义的自定义类进行运算符重载。该类称为“有理数”,代表有理数,例如117/1098。类的定义如下,我已经重载了一堆运算符,例如加号,减号,时间等等。但是我不确定如何重载“ in”运算符。

这是我的课程:

data class Rational(val rational: String) {
    private val numerator: BigInteger
    private val denominator: BigInteger

    init {
        val splitted = rational.split("/")
        numerator = splitted[0].toBigInteger()
        denominator = when (splitted[1]) {
            "0" -> throw Exception("not allowed")
            else -> splitted[1].toBigInteger()
        }
    }

    operator fun plus(number: Rational): Rational {
        val gcm = denominator * number.denominator
        val numerator = (gcm / denominator) * numerator + (gcm / number.denominator) * number.numerator
        return Rational("$numerator/$gcm")
    }

    operator fun minus(number: Rational): Rational {
        val gcm = denominator * number.denominator
        val numerator = (gcm / denominator) * numerator - (gcm / number.denominator) * number.numerator
        return Rational("$numerator/$gcm")
    }

    operator fun times(number: Rational): Rational {
        val numerator = numerator * number.numerator
        val denominator = denominator * number.denominator
        return Rational("$numerator/$denominator")
    }

    operator fun div(number: Rational): Rational {
        val numerator = numerator * number.denominator
        val denominator = denominator * number.numerator
        return Rational("$numerator/$denominator")
    }

    operator fun compareTo(number: Rational): Int {
        val ratio = this.numerator.toFloat() / this.denominator.toFloat()
        val numberRatio = number.numerator.toFloat() / number.denominator.toFloat()
        if (ratio > numberRatio) {
            return 1
        } else if (ratio == numberRatio) {
            return 0
        }
        return -1
    }

    operator fun unaryMinus(): Rational {
        val inverseNumerator = -numerator
        return Rational("$inverseNumerator/$denominator")
    }

    operator fun unaryPlus(): Rational {
        return Rational("$numerator/$denominator")
    }

    operator fun rangeTo(end: Rational): Any {
        var range: MutableList<Rational> = arrayListOf()
        val startNumerator = this.numerator.toInt()
        val endNumerator = end.numerator.toInt()
        var index = 0
        if (this.denominator == end.denominator) {
            for (i in startNumerator..endNumerator) {
                range.add(index, Rational("$i/$denominator"))
            }
        }
        return range
    }

    operator fun contains(number: Rational): Boolean {
        if (this.denominator % number.denominator == 0.toBigInteger()
                && this.numerator <= number.numerator) {
            return true
        }
        return false
    }

    override fun toString(): String {
        val gcd = numerator.gcd(denominator)
        return if (gcd != null) {
            val newNumerator = numerator / gcd
            val newDenominator = denominator / gcd
            "$newNumerator/$newDenominator"
        } else {
            "$numerator/$denominator"
        }
    }
}
infix fun Int.divBy(denominator: Int): Rational {
    if (denominator == 0) {
        throw Exception("denominator 0 not allowed")
    }

    return Rational("$this/$denominator")
}

infix fun Long.divBy(denominator: Long): Rational {
    if (denominator == 0L) {
        throw Exception("denominator 0 not allowed")
    }
    return Rational("$this/$denominator")
}

infix fun BigInteger.divBy(denominator: BigInteger): Rational {
    if (denominator == 0.toBigInteger()) {
        throw Exception("denominator 0 not allowed")
    }
    return Rational("$this/$denominator")
}

fun String.toRational(): Rational {
    return Rational(this)
}

这是我的主体,显然仍然无法编译:

fun main() {
    val half = 1 divBy 2
    val third = 1 divBy 3
    val twoThirds = 2 divBy 3

    println(half in third..twoThirds) // this line does not compile beacause in operator is not defined for the class
}

我想我必须重写“ rangeTo”运算符,但是我不确定该运算符的原型。我那里有人可以帮助我走上正确的路吗?

kotlin operator-keyword
3个回答
5
投票

使in工作的方法是使third..twoThirds调用返回something,该方法具有contains(Rational)方法,这是in调用所转换的。

执行此操作的一种方法是在此处返回ClosedRange<Rational>,如下所示:

operator fun rangeTo(end: Rational): ClosedRange<Rational> {
    return object : ClosedRange<Rational> {
        override val endInclusive: Rational = end
        override val start: Rational = this@Rational
    }
}

这对Rational施加了类型约束,因为ClosedRange需要实现ClosedRange才能确定值是否属于其中。您可以通过实现Comparable接口,然后将Comparable添加到现有的Comparable运算符中来进行此操作(此外,重命名参数以匹配该接口也是一种很好的做法):

operator

您也可以通过使用此实现来避免完全转换为浮点数,如@gidds在下面的注释中建议的那样:

compareTo

而且,您当前的compareTo实现可能可能被丢弃,因为您不再需要它,并且它的功能很奇怪。


要在此处添加除直接答案之外的内容:如@Eugene Petrenko在其答案中建议的那样,除了使用data class Rational(val rational: String) : Comparable<Rational> { ... override operator fun compareTo(other: Rational): Int { val ratio = this.numerator.toFloat() / this.denominator.toFloat() val numberRatio = other.numerator.toFloat() / other.denominator.toFloat() if (ratio > numberRatio) { return 1 } else if (ratio == numberRatio) { return 0 } return -1 } } 的构造函数外,添加几个构造函数(例如,使用两个override operator fun compareTo(other: Rational): Int { return (numerator * other.denominator - denominator * other.numerator).signum() } 的构造函数)是可行的。 s,一个需要两个contains


0
投票

String运算符被声明为反。您需要在右侧带有左侧的扩展功能。

Int

例如,您缺少插入功能BigIntegers,因此无法将in浏览到https://kotlinlang.org/docs/reference/operator-overloading.html#in中>]

divBy

不是像Int这样的代码将起作用。从理论上讲,从Rational开始为infix fun Int.divBy(i: Int) = Rational("$this/$i") 添加一个构造函数以避免解析。

val half = 1 divBy 2类的Rational方法中的返回类型错误,不应为Int。应该声明为

rangeTo

现在带有Rational的示例应该可以使用。

UPD:添加了RationalRange。我错过了重点,对不起。您完全不需要为Any类实现的data class RationalRange(val left: Rational, val right: Rational) { operator fun contains(r: Rational) = left <= r && r <= right } operator fun rangeTo(end: Rational): RationalRange(this, end) 函数。

x in a..bcontains函数不太可能使用Rational,您可以直接用整数来实现

一个简单的解决方案是在您的类中实现Comparable接口。

compareTo

然后使用您的比较逻辑来实现compareTo()函数。

Rational

这将解决编译错误,而无需使用自定义逻辑覆盖rangeTo()函数。


0
投票

一个简单的解决方案是在您的类中实现Comparable接口。

© www.soinside.com 2019 - 2024. All rights reserved.