В чем разница между ==и .equals()в Scala и когда какой использовать?
Реализация такая же, как в Java?
РЕДАКТИРОВАТЬ: в соответствующем вопросе говорится о конкретных случаях AnyVal. Более общий случай Any.
В чем разница между ==и .equals()в Scala и когда какой использовать?
Реализация такая же, как в Java?
РЕДАКТИРОВАТЬ: в соответствующем вопросе говорится о конкретных случаях AnyVal. Более общий случай Any.
scala.Equals котором указывается на Программирование на Scala, глава 28, Равенство объектов .
Ответы:
Обычно вы используете ==, он направляет equals, за исключением того, что обрабатывает nulls правильно. Ссылочное равенство (используется редко) есть eq.
3 == BigInt(3)и BigInt(3) == 3верны. Но 3.equals(BigInt(3))это ложь, тогда BigInt(3).equals(3)как правда. Поэтому предпочитаю использовать ==. Избегайте использования equals()в scala. Я думаю, ==что неявное преобразование хорошо, но equals()нет.
new java.lang.Integer(1) == new java.lang.Double(1.0)же правда, а new java.lang.Integer(1) equals new java.lang.Double(1.0)ложь?
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 не будет компилироваться, так как требует, чтобы оба аргумента были типа AnyRefnew ArrayList() equals new ArrayList()вернется true, поскольку он проверяет содержимоеnew ArrayList() == new ArrayList()вернется true, поскольку перенаправляет наequals(...)new ArrayList() eq new ArrayList()вернется false, поскольку оба аргумента являются разными экземплярамиfoo equals fooвернется true, если не fooбудет null, то броситNullPointerExceptionfoo == fooвернется true, даже если fooэтоnullfoo eq fooвернется true, поскольку оба аргумента ссылаются на одну и ту же ссылкуСуществует интересная разница между типами ==и 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: