web-dev-qa-db-fra.com

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

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

La mise en œuvre est-elle la même qu'en Java?

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

133
Jus12

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

184
Didier Dupont

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

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.

33
Don Roby

TL; DR

  • Remplacez la méthode equals pour comparer le contenu de chaque instance. C'est la même méthode equals que celle utilisée en Java
  • Utilisez l'opérateur == Pour comparer, sans vous soucier de null références
  • Utilisez la méthode eq pour vérifier si les deux arguments sont EXACTEMENT la même référence. Recommandé de ne pas utiliser à moins que vous ne compreniez comment cela fonctionne et souvent equals fonctionnera pour ce dont vous avez besoin à la place. Et assurez-vous de ne l'utiliser que avec AnyRef arguments, pas seulement Any

NOTE: Dans le cas de equals, tout comme en Java, il est possible que le résultat ne soit pas identique si vous changez les arguments, par exemple 1.equals(BigInt(1)) renverra false où l'inverse sera retourne true. Cela est dû au fait que chaque implémentation vérifie uniquement des types spécifiques. Les nombres primitifs ne vérifient pas si le second argument est de type Number ni BigInt mais uniquement d'autres types primitifs

Détails

La méthode AnyRef.equals(Any) est celle qui est surchargée par les sous-classes. Une méthode de la Java Spécification qui est passée à Scala aussi. Si elle est utilisée sur une instance sans boîte, elle est appelée pour cela (bien que cachée dans Scala ; plus évident dans Java avec int-> Integer). L'implémentation par défaut compare simplement les références (comme en Java).

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

La méthode AnyRef.eq(AnyRef) compare niquement références, c’est-à-dire où l’instance est située en mémoire. Il n'y a pas de boxe implicite pour cette méthode.

Exemples

  • 1 equals 2 Retournera false, car il redirige vers Integer.equals(...)
  • 1 == 2 Retournera false, car il redirige vers Integer.equals(...)
  • 1 eq 2 Ne compilera pas, car les deux arguments doivent être de type AnyRef
  • new ArrayList() equals new ArrayList() retournera true, car il vérifie le contenu
  • new ArrayList() == new ArrayList() retournera true, car il redirige vers equals(...)
  • new ArrayList() eq new ArrayList() retournera false, car les deux arguments sont des instances différentes
  • foo equals foo Retournera true, à moins que foo ne soit null, alors jettera un NullPointerException
  • foo == foo Retournera true, même si foo est null
  • foo eq foo Retournera true, car les deux arguments sont liés à la même référence
26
zjohn4

Il y a une différence intéressante entre == et equals pour Float et Double types: ils traitent NaN diffé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 quoi ceci est:

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 va imprimer

false
true
true

Ainsi, le unboxedNan donne false par rapport à l'égalité car c'est ainsi que les nombres à virgule flottante IEEE le définissent et cela devrait vraiment arriver dans tous les langages de programmation (bien que cela dérange en quelque sorte avec la notion d'identité) .

Le NaN encadré donne la valeur true pour la comparaison avec == in Java car nous comparons les références d’objet.

Je n'ai pas d'explication pour le cas equals, à mon humble avis, il devrait vraiment se comporter de la même manière que == sur les doubles valeurs non encaissées, mais ce n'est pas le cas.

Traduit en Scala le sujet est un peu plus compliqué que Scala a unifié les types primitif et objet dans Any et se traduit par la primitive double et la boîte double au besoin. Ainsi, le scala == se résume apparemment à une comparaison de valeurs primitives NaN mais equals utilise celle définie pour les valeurs Double encadrées (il y a beaucoup de magie de conversion implicite en cours et de trucs pimpés sur des doubles par RichDouble).

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

5
scravy

Dans Scala == commencez par vérifier Null valeurs puis appelez égal méthode sur le premier objet

1
jack