Qual é a diferença entre ==
e .equals()
no Scala e quando usar qual?
A implementação é a mesma que em Java?
EDIT: A pergunta relacionada fala sobre casos específicos de AnyVal
. O caso mais geral é Any
.
Qual é a diferença entre ==
e .equals()
no Scala e quando usar qual?
A implementação é a mesma que em Java?
EDIT: A pergunta relacionada fala sobre casos específicos de AnyVal
. O caso mais geral é Any
.
Respostas:
Você normalmente usa ==
, ele direciona para equals
, exceto que o trata null
corretamente. Igualdade de referência (raramente usada) é eq
.
3 == BigInt(3)
e BigInt(3) == 3
são verdadeiros. Mas, 3.equals(BigInt(3))
é falso, enquanto BigInt(3).equals(3)
é verdade. Portanto, prefira usar ==
. Evite usar equals()
na Scala. Eu acho ==
que a conversão implícita bem, mas equals()
não.
new java.lang.Integer(1) == new java.lang.Double(1.0)
é verdade enquanto new java.lang.Integer(1) equals new java.lang.Double(1.0)
é falso?
equals
método para comparar o conteúdo de cada instância. Este é o mesmo equals
método usado em Java==
operador para comparar, sem se preocupar com null
referênciaseq
método para verificar se os dois argumentos são EXATAMENTE a mesma referência. É recomendável não usar, a menos que você entenda como isso funciona e, muitas vezes equals
, funcionará para o que você precisa. E certifique-se de usar isso apenas com AnyRef
argumentos, não apenasAny
NOTA: No caso de equals
, assim como em Java, ele pode não retornar o mesmo resultado se você alternar os argumentos, por exemplo 1.equals(BigInt(1))
, retornará para false
onde o inverso retornará true
. Isso ocorre porque cada implementação verifica apenas tipos específicos. Números primitivos não verificam se o segundo argumento é de Number
nem BigInt
tipos, mas apenas de outros tipos primitivos
O AnyRef.equals(Any)
método é substituído por subclasses. Um método da Especificação Java que também chegou ao Scala. Se usado em uma instância sem caixa, é incluído na caixa para chamar isso (embora oculto no Scala; mais óbvio no Java com int
-> Integer
). A implementação padrão apenas compara referências (como em Java)
O Any.==(Any)
método compara dois objetos e permite que qualquer argumento seja nulo (como se estivesse chamando um método estático com duas instâncias). Ele compara se os dois são null
e chama o equals(Any)
método na instância em caixa.
O AnyRef.eq(AnyRef)
método compara apenas referências, é onde a instância está localizada na memória. Não há boxe implícito para esse método.
1 equals 2
retornará false
, pois ele redireciona paraInteger.equals(...)
1 == 2
retornará false
, pois ele redireciona paraInteger.equals(...)
1 eq 2
não será compilado, pois exige que ambos os argumentos sejam do tipo AnyRef
new ArrayList() equals new ArrayList()
retornará true
, pois verifica o conteúdonew ArrayList() == new ArrayList()
retornará true
, pois ele redireciona paraequals(...)
new ArrayList() eq new ArrayList()
retornará false
, pois os dois argumentos são instâncias diferentesfoo equals foo
retornará true
, a menos que foo
seja null
, então lançará umNullPointerException
foo == foo
retornará true
, mesmo que foo
sejanull
foo eq foo
retornará true
, pois os dois argumentos apontam para a mesma referênciaHá uma diferença interessante entre ==
e equals
para Float
e Double
tipos: Eles tratam de maneira NaN
diferente:
scala> Double.NaN == Double.NaN
res3: Boolean = false
scala> Double.NaN equals Double.NaN
res4: Boolean = true
Edit: Como foi apontado em um comentário - "isso também acontece em Java" - depende do que exatamente é isso :
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));
}
Isso imprimirá
false
true
true
Portanto, o unboxedNan
rendimento é false
comparado à igualdade, porque é assim que os números de ponto flutuante do IEEE o definem e isso deve realmente acontecer em todas as linguagens de programação (embora, de alguma forma, mexa com a noção de identidade).
O NaN em caixa rende true para a comparação usando ==
em Java, pois estamos comparando referências de objetos.
Eu não tenho uma explicação para o equals
caso, IMHO realmente deve se comportar da mesma forma que ==
em valores duplos sem caixa, mas não.
Traduzido para Scala, o assunto é um pouco mais complicado, pois Scala unificou tipos primitivos e de objetos Any
e se traduz no duplo primitivo e no duplo em caixa, conforme necessário. Assim, o scala ==
aparentemente se resume a uma comparação de NaN
valores primitivos , mas equals
usa o definido nos valores Double em caixa (há muita mágica de conversão implícita em andamento e há coisas adicionadas em dobro por RichDouble
).
Se você realmente precisa descobrir se algo realmente é NaN
usado isNaN
: