равно и 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
использует ==
в содержит (SortedSet
использует Ordering
вместо). И ==
звонит equals
.
Примечание: реализация моего первого equals
быстрая и грязная и, вероятно, плохая, если MyClass должен быть разделен на подклассы. Если это так, вы должны как минимум проверить равенство типов (this.getClass == that.getClass
) или лучше определить метод canEqual
(вы можете прочитать этот блог Даниэля Собрала)