wake-up-neo.com

Was ist der Unterschied zwischen == und .equals in Scala?

Was ist der Unterschied zwischen == Und .equals() in Scala und wann welche?

Ist die Implementierung dieselbe wie in Java?

EDIT: Die zugehörige Frage spricht über bestimmte Fälle von AnyVal. Der allgemeinere Fall ist Any.

133
Jus12

Normalerweise verwenden Sie == wird nach equals weitergeleitet, außer dass nulls ordnungsgemäß behandelt wird. Referenzgleichheit (selten verwendet) ist eq.

184
Didier Dupont

== ist eine letzte Methode und ruft .equals, was nicht endgültig ist.

Dies unterscheidet sich radikal von Java, wo == ist eher ein Operator als eine Methode und vergleicht streng die Referenzgleichheit für Objekte.

33
Don Roby

TL; DR

  • Überschreiben Sie die equals -Methode, um den Inhalt jeder Instanz zu vergleichen. Dies ist die gleiche equals Methode, die in Java verwendet wird
  • Verwenden Sie zum Vergleichen den Operator ==, Ohne sich Gedanken über null -Referenzen zu machen
  • Verwenden Sie die Methode eq, um zu überprüfen, ob beide Argumente GENAU dieselbe Referenz sind. Es wird empfohlen, nicht zu verwenden, es sei denn, Sie wissen, wie dies funktioniert, und equals funktioniert häufig für das, was Sie stattdessen benötigen. Und stellen Sie sicher, dass Sie dies nur mit AnyRef Argumenten verwenden, nicht nur mit Any

ANMERKUNG: Im Fall von equals wird, genau wie in Java, möglicherweise nicht dasselbe Ergebnis zurückgegeben, wenn Sie die Argumente umschalten. Beispiel: 1.equals(BigInt(1)) gibt false zurück, wohin die Umkehrung führt return true. Dies liegt daran, dass jede Implementierung nur bestimmte Typen überprüft. Primitive Zahlen prüfen nicht, ob das zweite Argument vom Typ Number oder BigInt ist, sondern nur von anderen primitiven Typen

Einzelheiten

Die AnyRef.equals(Any) -Methode wird von Unterklassen überschrieben. Eine Methode aus der Java Spezifikation, die auch in Scala verwendet wurde. Wenn sie für eine nicht gepackte Instanz verwendet wird, wird sie mit einem Kästchen versehen, um dies aufzurufen (obwohl sie in Scala verborgen ist ; offensichtlicher in Java mit int-> Integer). Die Standardimplementierung vergleicht lediglich Referenzen (wie in Java)

Die Any.==(Any) -Methode vergleicht zwei Objekte und lässt zu, dass eines der beiden Argumente null ist (als ob eine statische Methode mit zwei Instanzen aufgerufen würde). Es vergleicht, ob beide null sind, und ruft dann die equals(Any) -Methode für die Boxed-Instanz auf.

Die AnyRef.eq(AnyRef) -Methode vergleicht nur Referenzen, dh wo sich die Instanz im Speicher befindet. Für diese Methode gibt es kein implizites Boxen.

Beispiele

  • 1 equals 2 Gibt false zurück, während es zu Integer.equals(...) umleitet
  • 1 == 2 Gibt false zurück, während es zu Integer.equals(...) umleitet
  • 1 eq 2 Wird nicht kompiliert, da beide Argumente vom Typ AnyRef sein müssen.
  • new ArrayList() equals new ArrayList() gibt true zurück, während der Inhalt überprüft wird
  • new ArrayList() == new ArrayList() gibt true zurück, da es zu equals(...) umleitet
  • new ArrayList() eq new ArrayList() gibt false zurück, da beide Argumente unterschiedliche Instanzen sind
  • foo equals foo Gibt true zurück, es sei denn foo ist null, dann wirft NullPointerException
  • foo == foo Gibt true zurück, auch wenn foonull ist
  • foo eq foo Gibt true zurück, da beide Argumente auf dieselbe Referenz verweisen
26
zjohn4

Es gibt einen interessanten Unterschied zwischen == und equals für Float und Double Typen: Sie behandeln NaN unterschiedlich:

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

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

Edit: Wie in einem Kommentar ausgeführt - "das passiert auch in Java" - hängt davon ab, was genau dies ist ist:

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));
}

Dies wird gedruckt

false
true
true

Also, das unboxedNan ergibt false im Vergleich zur Gleichheit, denn so definieren es IEEE-Gleitkommazahlen und das sollte wirklich in jeder Programmiersprache passieren (obwohl es irgendwie mit dem Begriff der Identität zu tun hat) .

Die Boxed NaN ergibt true für den Vergleich mit == in Java beim Vergleichen von Objektreferenzen.

Ich habe keine Erklärung für den Fall equals, IMHO sollte es sich wirklich genauso verhalten wie == bei Doppelwerten ohne Box, aber nicht.

Übersetzt nach Scala die Sache ist etwas komplizierter als Scala hat Primitiv- und Objekttypen in Any vereinheitlicht und übersetzt in das Primitiv double and die Box Double nach Bedarf. So die scala == läuft anscheinend auf einen Vergleich von primitiven NaN Werten hinaus, aber equals verwendet den Wert, der für doppelte Werte definiert wurde (es gibt eine Menge impliziter Konvertierungsmagie und es gibt Dinge, die auf doppelte Werte aufgepeppt werden von RichDouble).

Wenn Sie wirklich herausfinden müssen, ob etwas tatsächlich NaN ist, verwenden Sie isNaN:

5
scravy

In Scala == zuerst nach Null Werten suchen und dann gleich Methode für erstes Objekt aufrufen

1
jack