Qual è la differenza tra == e .equals in Scala?


144

Qual è la differenza tra ==e .equals()in Scala e quando usare quale?

L'implementazione è la stessa di Java?

EDIT: la domanda correlata parla di casi specifici di AnyVal. Il caso più generale è Any.



@Ben Penso che le altre domande debbano essere contrassegnate come duplicate considerando la data richiesta. Inoltre, ritengo che le due domande siano diverse.
Jus12

Risposte:


201

Normalmente usi ==, si dirige verso equals, tranne per il fatto che tratta nulls correttamente. L'uguaglianza di riferimento (usata raramente) è eq.


12
Si applica anche quando si usano le librerie Java?
Jus12,

20
Lo fa. Ad esempio new java.util.ArrayList [Int] () == new java.util.ArrayList [Int] (), poiché uguale a ArrayList è l'uguaglianza dei contenuti.
Didier Dupont,

5
C'è anche uno strano comportamento in Int e Long e == contro .equals (). Lo stesso numero di Int e Long restituiscono true per == ma false per uguale a. Quindi == non indirizza sempre a uguali.
Harold L

24
Ancora più interessante, entrambi 3 == BigInt(3)e BigInt(3) == 3sono veri. Ma 3.equals(BigInt(3))è falso, mentre BigInt(3).equals(3)è vero. Pertanto, preferisci usare ==. Evitare l'uso equals()in scala. Penso ==che la conversione implicita bene, ma equals()non lo fa.
Naetmul,

Allora perché new java.lang.Integer(1) == new java.lang.Double(1.0)è vero mentre new java.lang.Integer(1) equals new java.lang.Double(1.0)è falso?
Eastsun

34

==è un metodo finale e chiama .equals, che non è definitivo.

Questo è radicalmente diverso da Java, dove ==è un operatore piuttosto che un metodo e confronta rigorosamente l'uguaglianza di riferimento per gli oggetti.


29

TL; DR

  • Sostituisci equalsmetodo per confrontare il contenuto di ogni istanza. Questo è lo stesso equalsmetodo utilizzato in Java
  • Usa l' ==operatore per confrontare, senza preoccuparti dei nullriferimenti
  • Utilizzare il eqmetodo per verificare se entrambi gli argomenti sono ESATTAMENTE lo stesso riferimento. Consigliato di non usare a meno che tu non capisca come funziona e spesso equalsfunzionerà per quello che ti serve invece. E assicurati di usarlo solo con AnyRefargomenti, non soloAny

NOTA: Nel caso di equals, proprio come in Java, potrebbe non restituire lo stesso risultato se si cambiano gli argomenti, ad es. 1.equals(BigInt(1))Si ritornerà falsedove ritornerà l'inverso true. Ciò è dovuto al fatto che ogni implementazione controlla solo tipi specifici. I numeri primitivi non controllano se il secondo argomento è di NumbernorBigInt tipi, ma solo di altri tipi primitivi

Dettagli

Il AnyRef.equals(Any)metodo è quello sovrascritto dalle sottoclassi. Un metodo dalle specifiche Java che è arrivato anche a Scala. Se utilizzato su un'istanza non in box, viene chiamato in box per chiamarlo (sebbene nascosto in Scala; più ovvio in Java con int-> Integer). L'implementazione predefinita confronta semplicemente i riferimenti (come in Java)

Il Any.==(Any)metodo confronta due oggetti e consente a entrambi gli argomenti di essere nulli (come se si chiamasse un metodo statico con due istanze). Confronta se entrambi lo sono null, quindi chiama il equals(Any)metodo sull'istanza in scatola.

Il AnyRef.eq(AnyRef)metodo confronta solo i riferimenti, ovvero dove si trova l'istanza in memoria. Non esiste un boxing implicito per questo metodo.

Esempi

  • 1 equals 2tornerà false, come reindirizza aInteger.equals(...)
  • 1 == 2tornerà false, come reindirizza aInteger.equals(...)
  • 1 eq 2 non verrà compilato, poiché richiede che entrambi gli argomenti siano di tipo AnyRef
  • new ArrayList() equals new ArrayList()tornerà true, mentre controlla il contenuto
  • new ArrayList() == new ArrayList()tornerà true, come reindirizza aequals(...)
  • new ArrayList() eq new ArrayList()ritornerà false, poiché entrambi gli argomenti sono istanze diverse
  • foo equals footornerà true, a meno che non foosia null, quindi lancerà aNullPointerException
  • foo == footornerà true, anche se lo fooènull
  • foo eq fooritornerà true, poiché entrambi gli argomenti si collegano allo stesso riferimento

6

C'è una differenza interessante tra ==e equalsper Floate Doubletipi: trattano NaNdiversamente:

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

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

Edit: come è stato sottolineato in un commento - "questo accade anche in Java" - dipende da cosa esattamente questo è il seguente:

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

Questo stamperà

false
true
true

Quindi, i unboxedNanrendimenti falsese confrontati per l'uguaglianza perché è così che lo definiscono i numeri in virgola mobile IEEE e questo dovrebbe realmente accadere in ogni linguaggio di programmazione (anche se in qualche modo si confonde con la nozione di identità).

Il NaN inscatolato produce true per il confronto utilizzando == in Java mentre stiamo confrontando i riferimenti agli oggetti.

Non ho una spiegazione per il equalscaso, IMHO dovrebbe davvero comportarsi come ==sui doppi valori non in scatola , ma non lo è.

Tradotto in Scala la questione è un po 'più complicata in quanto Scala ha unificato primitiva e tipi di oggetto in Anye si traduce nel doppio primitivo e nel doppio in scatola secondo necessità. Quindi la scala ==apparentemente si riduce a un confronto di NaNvalori primitivi ma equalsusa quello definito su valori Doppi in scatola (c'è molta magia di conversione implicita in corso e c'è roba addormentata su doppi RichDouble).

Se hai davvero bisogno di scoprire se qualcosa è effettivamente in NaNuso isNaN:


e questo succede anche in Java!
Iwan Satria,

4

In Scala == prima controlla i valori Null e poi chiama il metodo uguale sul primo oggetto

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.