Равная перегрузка с несколькими типами дает оператору '==', который нельзя применить к - PullRequest
2 голосов
/ 01 октября 2019

Здесь равная перегрузка

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'and' String '

Есть идеи?

1 Ответ

4 голосов
/ 02 октября 2019

Боюсь, это не может работать так, как вы хотите.

Для того, чтобы равенство велось так, как все ожидают, у него есть очень специфический контракт. (В документах по методу Kotlin Any.equals () изложены все необходимые условия, а в документах по методу Java Object.equals () есть немного больше информации.)

Одним из условий является то, что отношение равенства должно быть обратимым: a == b тогда и только тогда, когда b == a. (С технической точки зрения отношение должно быть симметричным .)

Но это не относится к вашей реализации:

  • myClass1.equals("ABCDEF") возвращает true (из MyClass реализация equals()), но
  • "ABCDEF".equals(myClass1) возвращает false (из вызова реализации String)

Системный класс, подобный String didn 'Я не знаю о вашем классе, и нет способа изменить его реализацию equals() так, как он. Так что, к сожалению, нет способа рассматривать его как равный, не нарушая контракт.

(Вы, вероятно, можете представить некоторые тонкие ошибки, которые могут вызвать: например, Set может содержать оба этих объекта, или простоодин, в зависимости от порядка, в который они были добавлены в…)

Ошибка компилятора, которую вы получаете, является косвенным результатом этого: если контракт equals() выполняется, несвязанные классы никогда будет рассматриваться как равный, поэтому компилятор даже не позволит вам попытаться сравнить их таким образом.

Из-за строгого контракта вы должны быть очень осторожны при реализации equals();а также симметрию, легко нарушить транзитивность и / или согласованность, и вам нужно переопределить hashCode() для соответствия. См. Например эти статьи . (И даже если вы контролируете оба класса, все равно удивительно сложно добиться равенства между ними; эта статья довольно хорошо объясняет проблемы.)

...