2010-09-17 7 views
22

In Programming in Scala schreiben die Autoren, dass Scala == Funktion Wertgleichheit anstelle von Referenzgleichheit vergleicht.Warum liefert die Funktion == von Array nicht wahr für Array (1,2) == Array (1,2)?

Dies funktioniert auf Listen wie erwartet:

scala> List(1,2) == List(1,2) 
res0: Boolean = true 

Es ist jedoch auf Arrays nicht funktioniert:

scala> Array(1,2) == Array(1,2) 
res1: Boolean = false 

Die Autoren empfehlen, stattdessen die sameElements Funktion zu verwenden:

scala> Array(1,2).sameElements(Array(1,2)) 
res2: Boolean = true 

Als Erklärung schreiben sie:

Obwohl dies wie eine Inkonsistenz erscheinen mag, ist es ein konservativer Ansatz seitens der Sprachentwickler, einen expliziten Test der Gleichheit zweier veränderbarer Datenstrukturen zu unterstützen. Auf lange Sicht sollte es Sie vor unerwarteten Ergebnissen in Ihren Bedingungen bewahren.

  1. Was bedeutet das? Welche Art von unerwartete Ergebnisse sprechen sie? Was könnte ich sonst von einem Array-Vergleich erwarten, als wenn true zurückgegeben würde, wenn die Arrays dieselben Elemente an derselben Position enthalten? Warum funktioniert die Gleichheitsfunktion unter List, aber nicht unter Array?

  2. Wie kann ich die Gleichheitsfunktion auf Arrays arbeiten lassen?

+0

Ich habe diese Erklärung auch in diesem Buch notiert. Es ist nicht korrekt, siehe meine eigene Antwort unten. Abgesehen von diesem Fehler ist das Buch sehr gut. –

+0

Man könnte kurz sagen, was vor sich geht als: "Java definiert die Wertgleichheit auf Arrays als Referenzgleichheit, nicht Element-für-Element-Gleichheit." –

+0

mögliches Duplikat von [Seltsames Verhalten des Array-Typs] (http://stackoverflow.com/questions/3213368/strange-behaviour-of-the-array-type) – Suma

Antwort

26

Es ist wahr, dass die Erklärung, die im Buch angeboten wird, fragwürdig ist, aber um ehrlich zu sein, war es glaubwürdiger, als sie es schrieben. Es ist immer noch richtig in 2.8, aber wir müssen verschiedene Überlegungen nachrüsten, denn wie Sie bereits festgestellt haben, führen alle anderen Sammlungen Elementvergleiche durch, auch wenn sie veränderbar sind.

Es wurde viel Blut vergossen, um Arrays wie den Rest der Sammlungen erscheinen zu lassen, aber das war eine extrem undichte Abstraktion und am Ende war es unmöglich. Es wurde festgestellt, richtigerweise denke ich, dass wir zum anderen Extrem gehen sollten und native Arrays so bereitstellen sollten, wie sie sind, indem wir implizite Maschinerie verwenden, um ihre Fähigkeiten zu verbessern. Am deutlichsten fällt dies auf toString und equals, weil keiner von ihnen sich in Arrays vernünftig verhält, aber wir können diese Aufrufe mit impliziten Konvertierungen nicht abfangen, weil sie auf java.lang.Object definiert sind. (Konvertierungen finden nur statt, wenn ein Ausdruck keine Prüfung eingibt und diese immer eine Prüfung eingibt.)

So können Sie Ihre Erklärung wählen, aber am Ende werden Arrays grundlegend anders durch die zugrunde liegende Architektur behandelt und es gibt keine Möglichkeit, dies zu überschlagen, ohne irgendwo einen Preis zu bezahlen. Es ist keine schreckliche Situation, aber Sie müssen sich dessen bewusst sein.

+0

Sie sagen also, dass die Sprachdesigner nicht denken, dass diese Inkonsequenz ein bemerkenswert gutes Design ist, sondern sehen Sie dies als den am wenigsten schmerzhaften Kompromiss an? –

+6

Für mich selbst zu sprechen, Programmierung ist wenig, aber "am wenigsten schmerzhafte Kompromisse", nicht dass dies mich daran hindert, es zu genießen. Und für den Rest der Welt zu sprechen, würde ich sagen, Ihre Paraphrase ist eine faire Zusammenfassung. – extempore

-3

Es geht um referentielle Transparenz. Die Idee ist, wenn zwei Werte == sind, sollte es egal sein, welche Sie für etwas verwenden. Wenn Sie zwei Arrays mit dem gleichen Inhalt haben, ist es wichtig, welche Sie ändern, also == gibt false zurück, es sei denn, sie sind die selben eins.

+0

Dies ist nicht korrekt! Scala implementiert == für alle Sammlungen außer Array. Siehe meine eigene Antwort. –

+0

Ich dachte, ich würde die 'eq' Funktion verwenden, um Referenzen in Scala zu vergleichen –

+0

Nun, ja. Verwenden Sie dazu die eq-Methode. Denken Sie jedoch daran, dass beim Erstellen einer Klasse (keine Fallklasse) == Verweise vergleicht, wenn Sie equals() nicht überschreiben. –

7

Diese genaue Frage wurde viele Male geäußert (von mir selbst, siehe Strange behaviour of the Array type).

Beachten Sie, dass es nur die Array Sammlung ist, die == nicht unterstützt, alle anderen Sammlungen tun. Die Ursache ist, dass Array das Java array ist.

+0

Warum haben die Sprachdesigner das Java 'array' als Standard' Array' anstelle von 'ArraySeq' oder' WrappedArray' gewählt, das sich wie erwartet verhält? –

+1

@Stefan - Weil die anderen primitive Typen boxen müssen und daher nicht so schnell laufen - genau dann, wenn Sie ein Array verwenden möchten. Auch wenn Java-Code verwendet wird, was viele tun, sind Arrays im Überfluss vorhanden. Somit ist das kleinere Übel, dass "Array" das Java-Array ist; die Kosten sind, dass sich "==" inkonsistent verhält. Außerdem gibt es keine offensichtliche Wahl für "Array". Sollte es "ArraySeq" sein? Wie wäre es mit 'ArrayBuffer'? Vielleicht 'WrappedArray'? Jeder von diesen hat anständige Gründe für das Bestehen, aber keiner ist der überwältigend naheliegende Kandidat. –

+0

Sie sagen also a) es war eine Leistungswahl b) Ich sollte normalerweise keine Arrays in Scala verwenden, also ist es egal, dass ihre 'equals' Funktion inkonsistent ist? –