J'ai un ensemble immuable d'une classe, Set [MyClass], et je veux utiliser les méthodes Set intersect et diff, mais je veux qu'ils testent l'égalité à l'aide de ma méthode égale personnalisée, plutôt que le test d'égalité d'objet par défaut
J'ai essayé de remplacer l'opérateur ==, mais il n'est pas utilisé.
Merci d'avance.
Éditer:
La méthode d'intersection est un membre de valeur concrète de 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
donc l'intersection se fait en utilisant la méthode du filtre.
Encore un autre Edit:
le filtre est défini dans TraversableLike
spec: http://www.scala-lang.org/api/current/scala/collection/TraversableLike.html
def filter(p: A => Boolean): Repr = {
val b = newBuilder
for (x <- this)
if (p(x)) b += x
b.result
}
Ce qui n'est pas clair pour moi, c'est ce qu'il utilise lorsqu'il est invoqué sans prédicat, p. Ce n'est pas un paramètre implicite.
equals et hashCode sont fournis automatiquement dans la classe case uniquement si vous ne les définissez pas.
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))
Si vous voulez une égalité de référence, écrivez toujours equals et hashCode, pour empêcher la génération automatique, et appelez la version depuis AnyRef
override def equals(o: Any) = super.equals(o)
override def hashCode = super.hashCode
Avec ça:
Set(MyClass("x"), MyClass("x"))
res2: scala.collection.immutable.Set[MyClass] = Set(MyClass(x), MyClass(x))
Vous ne pouvez pas remplacer le ==(o: Any)
d'AnyRef, qui est scellé et appelle toujours égal. Si vous avez essayé de définir un nouveau (surchargé) ==(m: MyClass)
, ce n'est pas celui que Set
appelle, donc il est inutile ici et assez dangereux en général.
Quant à l'appel à filter
, la raison pour laquelle cela fonctionne est que Set[A]
Est un Function[A, Boolean]
. Et oui, equals
est utilisé, vous verrez que l'implémentation de la fonction (apply
) est synonyme de contains
, et la plupart des implémentations de Set
utilisent ==
Dans contient (SortedSet
utilise le Ordering
à la place). Et ==
Appelle equals
.
Remarque: l'implémentation de mon premier equals
est rapide et sale et probablement mauvaise si MyClass doit être sous-classée. Si c'est le cas, vous devriez au moins vérifier l'égalité des types (this.getClass == that.getClass
) Ou mieux définir une méthode canEqual
(vous pouvez lire ce blog par Daniel Sobral)
Vous devrez remplacer .hashCode
ainsi que. C'est presque toujours le cas lorsque vous remplacez .equals
, comme .hashCode
est souvent utilisé comme pré-contrôle moins cher pour .equals
; deux objets égaux doivent avoir des codes de hachage identiques. Je suppose que vous utilisez des objets dont la valeur par défaut hashCode
ne respecte pas cette propriété en ce qui concerne votre égalité personnalisée, et l'implémentation de Set fait des hypothèses basées sur les codes de hachage (et donc jamais même en appelant votre opération d'égalité ).
Voir les documents Scala pour Any.equals
et Any.hashCode
: http://www.scala-lang.org/api/rc/scala/Any.html
Cette réponse montre un ensemble mutable personnalisé avec une égalité définie par l'utilisateur . Il pourrait être rendu immuable en remplaçant le magasin interne par un Vector
et en retournant une copie modifiée de lui-même à chaque opération
"Il n'est pas possible de remplacer directement ==, car il est défini comme méthode finale dans la classe Any. C'est-à-dire Scala traite == comme s'il était défini comme suit dans la classe Any:
final def == (that: Any): Boolean =
if (null eq this) {null eq that} else {this equals that}
"de Programming In Scala, deuxième édition