Qual é a diferença entre == e .equals no Scala?

144

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.

Jus12
fonte
@ Ben Eu acho que outra pergunta deve ser marcada como duplicada, considerando a data solicitada. Além disso, sinto que as duas perguntas são diferentes.
precisa saber é o seguinte

Respostas:

201

Você normalmente usa ==, ele direciona para equals, exceto que o trata nullcorretamente. Igualdade de referência (raramente usada) é eq.

Didier Dupont
fonte
12
Também se aplica ao usar bibliotecas Java?
Jus12
20
Faz. Por exemplo, novo java.util.ArrayList [Int] () == novo java.util.ArrayList [Int] (), como iguais em ArrayList é a igualdade de conteúdo.
Didier Dupont
5
Há também algum comportamento estranho em torno de Int e Long e == versus .equals (). O mesmo número que Int e Long retornam verdadeiro para ==, mas falso para iguais. Portanto, nem sempre o roteamento é igual a.
Harold L
24
Mais interessante, ambos 3 == BigInt(3)e BigInt(3) == 3sã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.
Naetmul
Então, por que 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?
Eastsun 13/09/16
34

==é um método final e chama .equals, que não é final.

Isso é radicalmente diferente do Java, onde ==é um operador e não um método e compara estritamente a igualdade de referência para objetos.

Don Roby
fonte
29

TL; DR

  • Substitua o equalsmétodo para comparar o conteúdo de cada instância. Este é o mesmo equalsmétodo usado em Java
  • Use o ==operador para comparar, sem se preocupar com nullreferências
  • Use o eqmé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 AnyRefargumentos, 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 falseonde 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 Numbernem BigInttipos, mas apenas de outros tipos primitivos

Detalhes

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 nulle 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.

Exemplos

  • 1 equals 2retornará false, pois ele redireciona paraInteger.equals(...)
  • 1 == 2retornará 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údo
  • new ArrayList() == new ArrayList()retornará true, pois ele redireciona paraequals(...)
  • new ArrayList() eq new ArrayList()retornará false, pois os dois argumentos são instâncias diferentes
  • foo equals fooretornará true, a menos que fooseja null, então lançará umNullPointerException
  • foo == fooretornará true, mesmo que foosejanull
  • foo eq fooretornará true, pois os dois argumentos apontam para a mesma referência
zjohn4
fonte
6

Há uma diferença interessante entre ==e equalspara Floate Doubletipos: Eles tratam de maneira NaNdiferente:

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 unboxedNanrendimento é falsecomparado à 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 equalscaso, 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 Anye se traduz no duplo primitivo e no duplo em caixa, conforme necessário. Assim, o scala ==aparentemente se resume a uma comparação de NaNvalores primitivos , mas equalsusa 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 é NaNusado isNaN:

scravy
fonte
e isso também acontece em Java!
Iwan Satria
4

Em Scala ==, primeiro verifique os valores Nulos e, em seguida, chama o método equals no primeiro objeto

jack
fonte