如何在 Kotlin 中为相关子类型实现 equals()

How to implement equals() for related subtypes in Kotlin

我正在尝试使用通用抽象超级 class 实现相关类型(例如 AST 节点)的 class 树。我正在尝试在子节点上实现 equals() ,以便不同的子类型确实不同,但是两个相似的类型可以对相等性进行更内省的计算。我试过这个:

abstract class Something {
    abstract fun equals(other:Something) : Boolean 
}

class Foo(val value:Int):Something() {
    override fun equals(other:Something) : Boolean {
        return (other as Foo).value == value
    }
}

class Bar(val value:Int):Something() {
    override fun equals(other:Something) : Boolean {
        return (other as Bar).value == value
    }
}

fun main(args: Array<String>) {
    val foo1:Something = Foo(1)  // if i don't type these as the abstract type
    val foo2:Something = Foo(1)  // then I it won't even let me check
    val bar1:Something = Bar(42) // if bar1 == foo1, because they're inferred
    val bar2:Something = Bar(42) // as different types
    println("foo1 == foo2 ${foo1 == foo2}") // should print true
    println("bar1 == bar2 ${bar1 == bar2}") // should print true
    println("foo1 == bar1 ${foo1 == bar2}") // should print false
}

不幸的是,所有 println 都只是显示错误。我做错了什么?错了?

  1. == 调用 Objectequals(Any?) 方法,而不是您的重载。所以你需要到处都有 override operator fun equals(other: Any?)

  2. 对于错误的类型,您的实现将抛出异常而不是返回 false,这很糟糕。相反,你需要

    // in Foo
    override fun equals(other: Any?) : Boolean = when (other) {
        is Foo -> other.value == value
        else -> false
    }
    

如果你想让==正常工作,你必须覆盖operator fun equals(other: Any?) : Boolean

如果你想明确要求在子类中实现,这样你就不会忘记它,你可以在超类中将其标记为abstract

abstract class Something {
    abstract override operator fun equals(other: Any?) : Boolean
}

class Foo(val value:Int):Something() {
    override fun equals(other: Any?): Boolean {
        return (other as Foo).value == value
    }
}

class Bar(val value:Int):Something() {
    override fun equals(other: Any?): Boolean {
        return (other as Bar).value == value
    }
}

当您使用语法 foo1 == foo2 Kotlin 调用函数时:

open operator fun equals(other: Any?): Boolean 

的 class Any 而不是您的自定义等于实现。

你需要使用语法 foo1.equals(foo2) 来做你想做的事。另外,就像 Alexey Romanov 在他的回答中指出的那样,你不能将 Foo 转换为 Bar 反之亦然,你需要这样做:

override fun equals(other:Something) : Boolean {
        return when(other) {
         is Foo -> other.value == value
         is Bar -> other.value == value
         else false
        }
    }

FooBar class 中。