Как я могу определить пользовательскую операцию равенства, которая будет использоваться неизменяемыми методами сравнения ссылок
У меня есть неизменяемый набор классов, 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. Это не неявный параметр.
Ответы
Ответ 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
Ответ 3
Этот ответ показывает настраиваемый изменяемый набор с определяемым пользователем Equality. Это можно было бы сделать неизменным, заменив внутреннее хранилище на Vector
и вернув измененную копию себя при каждой операции
Ответ 4
"Невозможно переопределить == напрямую, поскольку он определен как окончательный метод в классе Any. То есть Scala рассматривает ==, как если бы они были определены следующим образом в классе Any:
final def == (that: Any): Boolean =
if (null eq this) {null eq that} else {this equals that}
"из программирования В Scala, второе издание