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
.
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
.
Risposte:
Normalmente usi ==
, si dirige verso equals
, tranne per il fatto che tratta null
s correttamente. L'uguaglianza di riferimento (usata raramente) è eq
.
3 == BigInt(3)
e BigInt(3) == 3
sono 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.
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?
equals
metodo per confrontare il contenuto di ogni istanza. Questo è lo stesso equals
metodo utilizzato in Java==
operatore per confrontare, senza preoccuparti dei null
riferimentieq
metodo 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 equals
funzionerà per quello che ti serve invece. E assicurati di usarlo solo con AnyRef
argomenti, 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à false
dove 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 Number
norBigInt
tipi, ma solo di altri tipi primitivi
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.
1 equals 2
tornerà false
, come reindirizza aInteger.equals(...)
1 == 2
tornerà 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 contenutonew ArrayList() == new ArrayList()
tornerà true
, come reindirizza aequals(...)
new ArrayList() eq new ArrayList()
ritornerà false
, poiché entrambi gli argomenti sono istanze diversefoo equals foo
tornerà true
, a meno che non foo
sia null
, quindi lancerà aNullPointerException
foo == foo
tornerà true
, anche se lo foo
ènull
foo eq foo
ritornerà true
, poiché entrambi gli argomenti si collegano allo stesso riferimentoC'è una differenza interessante tra ==
e equals
per Float
e Double
tipi: trattano NaN
diversamente:
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 unboxedNan
rendimenti false
se 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 equals
caso, 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 Any
e si traduce nel doppio primitivo e nel doppio in scatola secondo necessità. Quindi la scala ==
apparentemente si riduce a un confronto di NaN
valori primitivi ma equals
usa 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 NaN
uso isNaN
: