等于多个类型的重载使运算符'=='无法应用于

时间:2019-10-01 20:52:38

标签: kotlin operator-overloading equals

这里等于重载

class MyClass {
    ...
    val string: String = ...

    override operator fun equals(other: Any?): Boolean {
        if (other != null) else { return false }
        if (other is MyClass && string == other.string) { return true }
        if (other is String && string == other) { return true }
        return false
    }
    ...
}

该想法是能够进行比较:

myClass1 = MyClass("ABCDEF")
myClass2 = MyClass("ABC123")

myClass1 == fsPath2  >> false
or
myClass1 == "ABC123" >> false

但是预编译说:运算符'=='不能应用于'MyClass'和'String'

有什么主意吗?

1 个答案:

答案 0 :(得分:4)

恐怕这无法按照您想要的方式进行。

为了使平等行为达到每个人的期望,它有一个非常具体的合同。 (Kotlin Any.equals()方法的文档说明了所有必要条件,而Java Object.equals()方法的文档则提供了更多信息。)

条件之一是相等关系必须是可逆的:a == b当且仅当b == a。 (从技术上讲,该关系必须是对称。)

但这对您的实现而言并非如此:

  • myClass1.equals("ABCDEF")返回true(来自MyClass的{​​{1}}实现),但是
  • equals()返回false(通过调用"ABCDEF".equals(myClass1)的实现)

String这样的系统类不了解您的类,因此无法更改其String实现。因此,不幸的是,在不违反合同的情况下,无法平等对待它。

(您可能会想象一些可能引起的细微错误:例如,一个Set可以容纳这两个对象,或者仅容纳一个,这取决于它们恰好被添加的顺序…)

您得到的编译器错误是由此导致的间接结果:假设equals()合同成立,则不相关的类将永远被视为相等,因此编译器不会甚至不能让您尝试那样比较它们。

由于合同严格,在实施equals()时需要格外小心;以及对称性,很容易破坏传递性和/或一致性,并且您需要覆盖equals()进行匹配。例如,请参见these articles。 (即使您同时控制两个类,也很难在它们之间实现相等性; this article很好地解释了这些问题。)