Kotlin реализация интерфейса ломает переопределение "равно" - PullRequest
1 голос
/ 02 марта 2020

У меня есть следующий класс, который служит базой для нескольких других классов:

abstract class BaseFitness: Comparable<BaseFitness> {
    var valid: Boolean = false
    fun invalidate() { valid = false }
    abstract fun value(): Double
    abstract fun copy(): BaseFitness

    override operator fun equals(other: Any?): Boolean =
        if (other is BaseFitness)
            this.value() == other.value()
        else
            throw IllegalArgumentException("Can only compare to another class derived from BaseFitness.")

    override fun compareTo(other: BaseFitness): Int =
        this.value().minus(other.value())
            .let { if (it.isNaN()) 0.0 else it }
            .sign.toInt()

    @JvmName("compareToOperator")
    operator fun compareTo(other: Any?): Int =
        if (other is BaseFitness)
            this.compareTo(other)
        else
            throw IllegalArgumentException("Can only compare to another class derived from BaseFitness.")
}

Теперь в этом классе я хочу реализовать базовое c поведение сравнения.

В основном Я хочу иметь возможность:

  1. if (fit1 == fit2) { /* do stuff */ }

  2. if (fit1 > fit2) { /* do stuff */ }

  3. if (fit1 < fit2) { /* do stuff */ }

  4. myFitnessSequence.max()

Функции оператора equals() и compareTo() заботятся о первых 3 элементах. Однако для последнего пункта мне нужно BaseFitness для реализации Comparable. Проблема в том, что когда я реализую сопоставимый и добавляю неоператорный метод compareTo(), то каким-то образом equals() разрывается с этим сообщением:

'operator' modifier is inapplicable on this function: must override ''equals()'' in Any

Я пытался сделать то же самое, что и с compareTo(), просто 2 реализации equals(), одна помечена как оператор, а другая оставлена ​​как метод и добавляет @JvmName к одной из них, и я получаю

'@JvmName' annotation is not applicable to this declaration

Прямо сейчас мои варианты в основном либо выбрать сохранить и == оператор, но не реализующий Comparable или отказ от == для использования сопоставимого.

1 Ответ

2 голосов
/ 02 марта 2020

Вам не нужно отмечать equals и compareTo ключевым словом operator, оба они уже определены как оператор в своих соответствующих типах. В случае equals, Any определяет его как operator, а compareTo помечается как operator в Comparable interface.

Так что все, что вам нужно сделать, это предоставить их реализации путем переопределения их.

С Kotlin в действии

Относительно метода равных

Функция equals отмечена как override, потому что, в отличие от других соглашений, метод, реализующий ее, определен в классе Any (сравнение равенства поддерживается для всех объектов в Kotlin). Это также объясняет, почему вам не нужно помечать его как оператор: базовый метод в Any помечается так: , а модификатор оператора для метода применяется также ко всем методам, которые реализуют или переопределяют его .

Относительно сопоставимого интерфейса

Kotlin поддерживает тот же сопоставимый интерфейс. Но метод compareTo, определенный в этом интерфейсе, может быть вызван соглашением, и использование операторов сравнения ('<', '>', <= и> =) транслируется в вызовы compareTo.

...