Jaka jest różnica między ==i .equals()w Scala, a kiedy używać które?
Czy implementacja jest taka sama jak w Javie?
EDYCJA: Powiązane pytanie dotyczy konkretnych przypadków AnyVal. Bardziej ogólny przypadek to Any.
Jaka jest różnica między ==i .equals()w Scala, a kiedy używać które?
Czy implementacja jest taka sama jak w Javie?
EDYCJA: Powiązane pytanie dotyczy konkretnych przypadków AnyVal. Bardziej ogólny przypadek to Any.
Odpowiedzi:
Zwykle używasz ==, kieruje do equals, z wyjątkiem tego, że traktuje je nullpoprawnie. Równość odwołań (rzadko używana) to eq.
3 == BigInt(3)i BigInt(3) == 3są prawdziwe. Ale 3.equals(BigInt(3))jest fałszywe, podczas gdy BigInt(3).equals(3)jest prawdziwe. Dlatego wolę używać ==. Unikaj używania equals()w scali. Myślę, że ==niejawna konwersja dobrze equals()działa , ale tak nie jest.
new java.lang.Integer(1) == new java.lang.Double(1.0)jest prawdziwe, podczas gdy new java.lang.Integer(1) equals new java.lang.Double(1.0)jest fałszywe?
equals, aby porównać zawartość każdego wystąpienia. To ta sama equalsmetoda, która jest używana w Javie==operatora do porównania, nie martwiąc się o nullodwołaniaeqmetody, aby sprawdzić, czy oba argumenty są DOKŁADNIE tym samym odwołaniem. Zaleca się, aby nie używać, chyba że rozumiesz, jak to działa i często equalsbędzie działać w przypadku tego, czego potrzebujesz. I upewnij się, że używasz tego tylko z AnyRefargumentami, a nie tylkoAnyUWAGA: W przypadku equals, tak jak w Javie, może nie zwrócić tego samego wyniku, jeśli zmienisz argumenty, np. 1.equals(BigInt(1))Zwróci falsetam, gdzie zwróci odwrotność true. Dzieje się tak, ponieważ każda implementacja sprawdza tylko określone typy. Liczby pierwotne nie sprawdzają, czy drugi argument jest typu Numbernor, BigIntale tylko innych typów pierwotnych
AnyRef.equals(Any)Metoda jest jedną zastąpione przez podklasy. Metoda ze specyfikacji Java, która również trafiła do Scali. Jeśli jest używany w instancji bez opakowania, jest zaznaczony, aby to wywołać (choć ukryty w Scali; bardziej oczywiste w Javie z int-> Integer). Domyślna implementacja jedynie porównuje referencje (jak w Javie)
Any.==(Any)Sposób porównuje dwa przedmioty i pozwala oba argumenty będą puste (jak wywołanie statyczne metody z dwóch przypadkach). Porównuje, jeśli oba są null, a następnie wywołuje equals(Any)metodę w pudełkowej instancji.
AnyRef.eq(AnyRef)Sposób porównuje tylko odniesienia, to jest, gdy przykład znajduje się w pamięci. W przypadku tej metody nie ma niejawnego boksu.
1 equals 2powróci false, ponieważ przekierowuje doInteger.equals(...)1 == 2powróci false, ponieważ przekierowuje doInteger.equals(...)1 eq 2 nie skompiluje się, ponieważ wymaga, aby oba argumenty były typu AnyRefnew ArrayList() equals new ArrayList()zwróci true, ponieważ sprawdza zawartośćnew ArrayList() == new ArrayList()powróci true, ponieważ przekierowuje doequals(...)new ArrayList() eq new ArrayList()zwróci false, ponieważ oba argumenty są różnymi wystąpieniamifoo equals foozwróci true, chyba że foojest null, a następnie wyrzuciNullPointerExceptionfoo == foopowróci true, nawet jeśli foojestnullfoo eq foozwróci wartość true, ponieważ oba argumenty prowadzą do tego samego odwołaniaIstnieje interesująca różnica między typami ==i equalsdla Floatoraz Double: traktują one NaNinaczej:
scala> Double.NaN == Double.NaN
res3: Boolean = false
scala> Double.NaN equals Double.NaN
res4: Boolean = true
Edit: Jak wskazano w komentarzu - „tak się dzieje również w Javie” - zależy od tego, co dokładnie to jest:
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));
}
To się wydrukuje
false
true
true
Tak więc unboxedNanwydajność falseporównana pod kątem równości, ponieważ tak definiują ją liczby zmiennoprzecinkowe IEEE i powinno to naprawdę mieć miejsce w każdym języku programowania (chociaż w jakiś sposób miesza się z pojęciem tożsamości).
Pole NaN daje wartość true dla porównania używanego ==w Javie, gdy porównujemy odwołania do obiektów.
Nie mam wytłumaczenia dla equalssprawy, IMHO to naprawdę powinno zachowywać się tak samo jak ==na unboxed double wartości, ale tak nie jest.
W tłumaczeniu na Scala sprawa jest trochę bardziej skomplikowana, ponieważ Scala ujednolicił typy prymitywne i obiektowe na Anyi tłumaczy na prymitywne podwójne i pudełkowe podwójne w razie potrzeby. Tak więc skala ==najwyraźniej sprowadza się do porównania NaNwartości pierwotnych , ale equalswykorzystuje tę zdefiniowaną na opakowanych wartościach Double (dzieje się wiele niejawnej magii konwersji i jest coś podwojonego przez podwójne RichDouble).
Jeśli naprawdę chcesz się dowiedzieć, czy coś jest rzeczywiście NaNużywane isNaN: