Чтобы заставить in
работать, вызов third..twoThirds
возвращает что-то , которое имеет метод 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
необходимоComparable
реализация, чтобы иметь возможность определить, принадлежит ли значение в нем.Это можно сделать, внедрив интерфейс Comparable
, а затем добавив operator
к существующему оператору compareTo
(плюс рекомендуется переименовать параметр в соответствии с интерфейсом):
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
}
}
Вы также можете полностью избежать преобразования в числа с плавающей точкой, используя вместо этого эту реализацию, как предложено в комментарии ниже @gidds:
override operator fun compareTo(other: Rational): Int {
return (numerator * other.denominator - denominator * other.numerator).signum()
}
Кроме того, ваша текущая реализация contains
может вероятно будет отброшено, так как оно вам больше не нужно, и оно функционирует довольно странно.
Чтобы добавить что-то кроме прямого ответа здесь: как предложил Евгений Петренко в своем ответе,было бы целесообразно добавить пару конструкторов, отличных от того, который использует String
, например, тот, который занимает два Int
с, и один, который занимает два BigIntegers
с.