Подтвердить что ты не робот

Как я могу определить пользовательскую операцию равенства, которая будет использоваться неизменяемыми методами сравнения ссылок

У меня есть неизменяемый набор классов, Set [MyClass], и я хочу использовать методы Set intersect и diff, но я хочу, чтобы они проверяли равенство, используя мой собственный метод equals, а не тест на равенство по умолчанию

Я попытался переопределить оператор ==, но он не используется.

Спасибо заранее.

Edit:

Метод пересечения представляет собой конкретный элемент значения GenSetLike

spec: http://www.scala-lang.org/api/current/scala/collection/GenSetLike.html src: https://lampsvn.epfl.ch/trac/scala/browser/scala/tags/R_2_9_1_final/src//library/scala/collection/GenSetLike.scala#L1

def intersect(that: GenSet[A]): Repr = this filter that

поэтому пересечение выполняется с использованием метода фильтра.

Еще одно Edit:

Фильтр

определяется в TraversableLike

spec: http://www.scala-lang.org/api/current/scala/collection/TraversableLike.html

src: https://lampsvn.epfl.ch/trac/scala/browser/scala/tags/R_2_9_1_final/src//library/scala/collection/TraversableLike.scala#L1

def filter(p: A => Boolean): Repr = {
  val b = newBuilder
      for (x <- this) 
        if (p(x)) b += x
      b.result
}

Для меня непонятно, что он использует при вызове без предиката, p. Это не неявный параметр.

4b9b3361

Ответ 1

equals и hashCode предоставляются автоматически в случае класса только в том случае, если вы их не определяете.

case class MyClass(val name: String) {
  override def equals(o: Any) = o match {
    case that: MyClass => that.name.equalsIgnoreCase(this.name)
    case _ => false
  }
  override def hashCode = name.toUpperCase.hashCode
}

Set(MyClass("xx"), MyClass("XY"), MyClass("xX"))
res1: scala.collection.immutable.Set[MyClass] = Set(MyClass(xx), MyClass(XY))

Если вы хотите использовать ссылочное равенство, все равно напишите equals и hashCode, чтобы предотвратить автоматическое создание, и вызовите версию из AnyRef

  override def equals(o: Any) = super.equals(o)
  override def hashCode = super.hashCode

С этим:

Set(MyClass("x"), MyClass("x"))
res2: scala.collection.immutable.Set[MyClass] = Set(MyClass(x), MyClass(x))

Вы не можете переопределить ==(o: Any) из AnyRef, который запечатан и всегда называет равным. Если вы попытались определить новый (перегруженный) ==(m: MyClass), это не тот, который вызывает Set, поэтому он бесполезен здесь и довольно опасен вообще.

Что касается вызова filter, причина его работы в том, что Set[A] является Function[A, Boolean]. И да, используется equals, вы увидите, что реализация функции (apply) является синонимом для contains, а большинство реализаций Set use == in contains (SortedSet использует Ordering вместо). И == вызывает equals.


Примечание: реализация моего первого equals является быстрым и грязным и, вероятно, плохим, если MyClass должен быть подклассом. Если это так, вы должны, по крайней мере, проверить тип равенства (this.getClass == that.getClass) или лучше определить метод canEqual (вы можете прочитать этот блог Даниэль Собрал)

Ответ 2

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

Смотрите документы Scala для Any.equals и Any.hashCode: http://www.scala-lang.org/api/rc/scala/Any.html

Ответ 4

"Невозможно переопределить == напрямую, поскольку он определен как окончательный метод в классе Any. То есть Scala рассматривает ==, как если бы они были определены следующим образом в классе Any:

    final def == (that: Any): Boolean =
      if (null eq this) {null eq that} else {this equals that}

"из программирования В Scala, второе издание