Kotlin 接口实现打破了“等于”覆盖

Kotlin interface implementation breaks `equals` overriding

我有以下 class 作为其他一些 classes 的基础:

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.")
}

现在,在这个 class 中,我想实现基本的比较行为。

基本上我希望能够做到:

  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 要么放弃 == 使用 comparable.

您不需要用 operator 关键字标记 equalscompareTo,它们都已在各自的类型中定义为运算符。 在 equals 的情况下,Any 将其定义为 operator 并且 compareToComparable interface 中标记为 operator.

所以您所要做的就是通过覆盖它们来提供它们的实现。

来自Kotlin in Action

Regarding the equals method

The equals function is marked as override, because, unlike other conventions, the method implementing it is defined in the Any class (equality comparison is supported for all objects in Kotlin). That also explains why you don’t need to mark it as operator: the base method in Any is marked as such, and the operator modifier on a method applies also to all methods that implement or override it.

Regarding the Comparable interface

Kotlin supports the same Comparable interface. But the compareTo method defined in that interface can be called by convention, and uses of comparison operators ('<', '>', <=, and >=) are translated into calls of compareTo.