В чем разница между == и .equals в Scala?


150

В чем разница между ==и .equals()в Scala и когда какой использовать?

Реализация такая же, как в Java?

РЕДАКТИРОВАТЬ: в соответствующем вопросе говорится о конкретных случаях AnyVal. Более общий случай Any.



@Ben Я думаю, что другой вопрос следует пометить как повторяющийся, учитывая заданную дату. Кроме того, я считаю, что это разные вопросы.
— Jus12 07

Ответы:


205

Обычно вы используете ==, он направляет equals, за исключением того, что обрабатывает nulls правильно. Ссылочное равенство (используется редко) есть eq.


12
Применяется ли это также при использовании библиотек Java?
— Jus12 06

20
Оно делает. Например, new java.util.ArrayList [Int] () == new java.util.ArrayList [Int] (), равным в ArrayList является равенство содержимого.
— Дидье Дюпон

5
Также есть странное поведение с Int и Long и == по сравнению с .equals (). То же число, что и Int и Long, возвращают true для ==, но false для equals. Итак, == не всегда направляет на равные.
— Harold L

24
Что еще интереснее, оба 3 == BigInt(3)и BigInt(3) == 3верны. Но 3.equals(BigInt(3))это ложь, тогда BigInt(3).equals(3)как правда. Поэтому предпочитаю использовать ==. Избегайте использования equals()в scala. Я думаю, ==что неявное преобразование хорошо, но equals()нет.
— Naetmul

Так почему new java.lang.Integer(1) == new java.lang.Double(1.0)же правда, а new java.lang.Integer(1) equals new java.lang.Double(1.0)ложь?
— Eastsun

37

==это последний метод и вызывает .equals, который не является окончательным.

Это радикально отличается от Java, где ==оператор, а не метод, строго сравнивает ссылочное равенство для объектов.


31

TL; DR

  • equalsМетод переопределения для сравнения содержимого каждого экземпляра. Это тот же equalsметод, который используется в Java
  • Используйте ==оператор для сравнения, не беспокоясь о nullссылках
  • Используйте eqметод, чтобы проверить, являются ли оба аргумента ТОЧНО одной и той же ссылкой. Не рекомендуется использовать, если вы не понимаете, как это работает, и equalsвместо этого часто срабатывает то, что вам нужно. И убедитесь, что вы используете это только с AnyRefаргументами, а не толькоAny

ПРИМЕЧАНИЕ. В случае equals, как и в Java, он может не вернуть тот же результат, если вы переключите аргументы, например 1.equals(BigInt(1)), вернет falseтуда, где вернется обратное true. Это связано с тем, что каждая реализация проверяет только определенные типы. Примитивные числа не проверяют, имеет ли второй аргумент Numberни BigIntтипы, а только другие примитивные типы

Детали

AnyRef.equals(Any)Метод является одним переопределен подклассами. Метод из спецификации Java, который также перешел в Scala. Если он используется в распакованном экземпляре, он помещается в рамку для вызова этого (хотя и скрыт в Scala; более очевиден в Java с помощью int-> Integer). Реализация по умолчанию просто сравнивает ссылки (как в Java)

Этот Any.==(Any)метод сравнивает два объекта и позволяет любому аргументу иметь значение NULL (как при вызове статического метода с двумя экземплярами). Он сравнивает, если оба они есть null, а затем вызывает equals(Any)метод для экземпляра в штучной упаковке.

AnyRef.eq(AnyRef)Метод сравнивает только ссылки, то есть , где экземпляр находится в памяти. Для этого метода нет неявной упаковки.

Примеры

  • 1 equals 2вернется false, поскольку перенаправляет наInteger.equals(...)
  • 1 == 2вернется false, поскольку перенаправляет наInteger.equals(...)
  • 1 eq 2 не будет компилироваться, так как требует, чтобы оба аргумента были типа AnyRef
  • new ArrayList() equals new ArrayList()вернется true, поскольку он проверяет содержимое
  • new ArrayList() == new ArrayList()вернется true, поскольку перенаправляет наequals(...)
  • new ArrayList() eq new ArrayList()вернется false, поскольку оба аргумента являются разными экземплярами
  • foo equals fooвернется true, если не fooбудет null, то броситNullPointerException
  • foo == fooвернется true, даже если fooэтоnull
  • foo eq fooвернется true, поскольку оба аргумента ссылаются на одну и ту же ссылку

Можете ли вы также объяснить === в scala?
— user2441441

6

Существует интересная разница между типами ==и equalsfor Floatи Double: они относятся по- NaNразному:

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

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

Изменить: Как было отмечено в комментарии - «это также происходит в Java» - зависит от того, что именно это является:

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

Это напечатает

false
true
true

Таким образом, unboxedNanурожайность falseпри сравнении на равенство, потому что это то, как числа с плавающей запятой IEEE определяют это, и это действительно должно происходить на каждом языке программирования (хотя это как-то портит понятие идентичности).

Поле NaN в рамке дает значение true для сравнения, которое используется ==в Java, поскольку мы сравниваем ссылки на объекты.

У меня нет объяснения этому equalsслучаю, ИМХО, он действительно должен вести себя так же, как и ==с неупакованными двойными значениями, но это не так.

В переводе на Scala дело обстоит немного сложнее, так как Scala объединила примитивные и объектные типы в Anyпримитивный двойной и упакованный в штучный двойной тип и при необходимости преобразует их. Таким образом, scala, по- ==видимому, сводится к сравнению примитивных NaNзначений, но equalsиспользует тот, который определен для значений Double в штучной упаковке (происходит много неявной магии преобразования, и есть вещи, которые накладываются на двойные значения RichDouble).

Если вам действительно нужно узнать, действительно ли что-то NaNиспользуется isNaN:


и это тоже происходит в Java!
— Iwan Satria

4

В Scala == сначала проверьте значения Null, а затем вызовите метод equals для первого объекта

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.