Quelle est la différence entre == et .equals dans Scala?

144

Quelle est la différence entre ==et .equals()dans Scala, et quand utiliser lequel?

L'implémentation est-elle la même qu'en Java?

EDIT: La question connexe parle de cas spécifiques de AnyVal. Le cas le plus général est Any.

Jus12
la source
@Ben Je pense que l'autre question devrait être marquée comme duplicata compte tenu de la date demandée. De plus, je pense que les deux questions sont différentes.
Jus12

Réponses:

201

Vous utilisez normalement ==, il achemine vers equals, sauf qu'il traite nulls correctement. L'égalité de référence (rarement utilisée) est eq.

Didier Dupont
la source
12
S'applique-t-il également lors de l'utilisation de bibliothèques Java?
Jus12
20
Cela fait. Par exemple, new java.util.ArrayList [Int] () == new java.util.ArrayList [Int] (), comme égal sur ArrayList est l'égalité de contenu.
Didier Dupont
5
Il y a aussi un comportement étrange autour de Int et Long et == contre .equals (). Le même nombre que Int et que Long renvoie vrai pour == mais faux pour égal. Donc == n'est pas toujours acheminé vers des égaux.
Harold L
24
Plus intéressant encore, les deux 3 == BigInt(3)et BigInt(3) == 3sont vrais. Mais, 3.equals(BigInt(3))est faux, alors que BigInt(3).equals(3)c'est vrai. Par conséquent, préférez utiliser ==. Évitez d'utiliser equals()dans scala. Je pense ==que la conversion implicite bien, mais equals()pas.
Naetmul
Alors pourquoi new java.lang.Integer(1) == new java.lang.Double(1.0)est-ce vrai alors que new java.lang.Integer(1) equals new java.lang.Double(1.0)c'est faux?
Eastsun
34

==est une méthode finale, et appelle .equals, qui n'est pas définitive.

Ceci est radicalement différent de Java, où ==est un opérateur plutôt qu'une méthode et compare strictement l'égalité de référence pour les objets.

Don Roby
la source
29

TL; DR

  • Override equalsméthode pour comparer le contenu de chaque instance. C'est la même equalsméthode utilisée en Java
  • Utilisez un ==opérateur pour comparer, sans vous soucier des nullréférences
  • Utilisez la eqméthode pour vérifier si les deux arguments sont exactement la même référence. Il est recommandé de ne pas utiliser à moins que vous ne compreniez comment cela fonctionne et fonctionnera souvent equalspour ce dont vous avez besoin à la place. Et assurez-vous de ne l'utiliser qu'avec des AnyRefarguments, pas seulementAny

REMARQUE: dans le cas de equals, tout comme en Java, il peut ne pas renvoyer le même résultat si vous changez d'arguments, par exemple 1.equals(BigInt(1))retournera falselà où l'inverse retournera true. Cela est dû au fait que chaque implémentation ne vérifie que des types spécifiques. Les nombres primitifs ne vérifient pas si le deuxième argument est de types Numberni BigIntmais uniquement d'autres types primitifs

Détails

La AnyRef.equals(Any)méthode est celle remplacée par les sous-classes. Une méthode de la spécification Java qui est également venue à Scala. S'il est utilisé sur une instance sans boîte, il est encadré pour l'appeler (bien que caché dans Scala; plus évident en Java avec int-> Integer). L'implémentation par défaut compare simplement les références (comme en Java)

La Any.==(Any)méthode compare deux objets et autorise l'un ou l'autre des arguments à être nul (comme pour appeler une méthode statique avec deux instances). Il compare si les deux sont null, puis il appelle la equals(Any)méthode sur une instance encadrée.

La AnyRef.eq(AnyRef)méthode compare uniquement les références, c'est-à-dire l'emplacement de l'instance en mémoire. Il n'y a pas de boxe implicite pour cette méthode.

Exemples

  • 1 equals 2reviendra false, car il redirige versInteger.equals(...)
  • 1 == 2reviendra false, car il redirige versInteger.equals(...)
  • 1 eq 2 ne compilera pas, car les deux arguments doivent être de type AnyRef
  • new ArrayList() equals new ArrayList()reviendra true, car il vérifie le contenu
  • new ArrayList() == new ArrayList()reviendra true, car il redirige versequals(...)
  • new ArrayList() eq new ArrayList()retournera false, car les deux arguments sont des instances différentes
  • foo equals foosera de retour true, à moins fooest null, puis va lancer uneNullPointerException
  • foo == foosera de retour true, même si fooestnull
  • foo eq fooretournera true, puisque les deux arguments sont liés à la même référence
zjohn4
la source
6

Il existe une différence intéressante entre ==et equalspour Floatet les Doubletypes: Ils traitent NaNdifféremment:

scala> Double.NaN == Double.NaN
res3: Boolean = false

scala> Double.NaN equals Double.NaN
res4: Boolean = true

Edit: Comme cela a été souligné dans un commentaire - "cela se produit également en Java" - dépend de ce que c'est exactement :

public static void main(final String... args) {
    final double unboxedNaN = Double.NaN;
    final Double boxedNaN = Double.valueOf(Double.NaN);

    System.out.println(unboxedNaN == unboxedNaN);
    System.out.println(boxedNaN == boxedNaN);
    System.out.println(boxedNaN.equals(boxedNaN));
}

Cela imprimera

false
true
true

Donc, les unboxedNanrendements falsecomparés pour l'égalité parce que c'est ainsi que les nombres à virgule flottante IEEE le définissent et cela devrait vraiment se produire dans chaque langage de programmation (bien que cela perturbe en quelque sorte la notion d'identité).

Le NaN encadré donne vrai pour la comparaison utilisant ==en Java pendant que nous comparons les références d'objet.

Je n'ai pas d'explication pour le equalscas, ==à mon humble avis , il devrait vraiment se comporter de la même manière que sur les valeurs doubles sans boîte, mais ce n'est pas le cas.

Traduit en Scala, la question est un peu plus compliquée car Scala a unifié les types primitifs et objets en Anyet se traduit par le double primitif et le double encadré si nécessaire. Ainsi, la scala ==se résume apparemment à une comparaison de NaNvaleurs primitives mais equalsutilise celle définie sur les valeurs Double encadrées (il y a beaucoup de magie de conversion implicite en cours et il y a des choses qui sont pimpées sur des doubles RichDouble).

Si vous avez vraiment besoin de savoir si quelque chose est réellement NaNutilisé isNaN:

scravy
la source
et cela se produit également en Java!
Iwan Satria
4

Dans Scala == vérifiez d'abord les valeurs Null , puis appelle la méthode equals sur le premier objet

jack
la source