Was ist der Unterschied zwischen int * int
und (int * int)
dort? Der einzige Unterschied, den ich sehe, ist die Mustererkennung:
Ist es nur ein syntaktischer Zucker? Wie wählen Sie aus, welche zu verwenden? Gibt es Leistungsunterschiede zwischen diesen beiden Formen?
Ja, es gibt einen Leistungsunterschied:
Im Speicher enthält A (23, 42)
ein Tag, das es als A
und die beiden ganzen Zahlen 23 und 42 identifiziert. B (23, 42)
enthält ein Tag, das es als B
identifiziert und einen Zeiger auf ein Tupel mit den ganzen Zahlen 23
und 42
. Es wird also eine zusätzliche Speicherzuweisung geben, wenn ein B
und eine zusätzliche Indirektionsebene beim Zugriff auf die einzelnen Werte innerhalb eines B
erstellt wird. In Fällen, in denen Sie die Konstruktorargumente nicht tatsächlich als Tupel verwenden, wird die Verwendung von A
weniger Overhead erfordern als die Verwendung von B
.
Andererseits wird Ihre test_foo
-Funktion jedes Mal, wenn sie mit einem A
-Wert aufgerufen wird, ein neues Tupel erzeugen, aber wenn sie mit einem B
-Wert aufgerufen wird, gibt sie einfach das Tupel zurück, das bereits existiert Erinnerung. Daher ist test_foo
für B
eine kostengünstigere Operation als für A
. Wenn Sie also die Argumente des Konstruktors als Tupel verwenden und dies mehrmals für denselben Wert tun, wird die Verwendung von B
günstiger.
Wenn Sie also die Konstruktorargumente als Tupel verwenden möchten, ist es sinnvoll, einen Konstruktor zu verwenden, der ein Tupel verwendet, weil Sie mit dem Mustervergleich mit weniger Code auf das Tupel zugreifen können, und weil Sie so nicht erstellen müssen tupelt denselben Wert mehrmals. In allen anderen Fällen ist die Verwendung eines Tupels vorzuziehen, da es weniger Speicherzuweisung und weniger Umleitung erfordert.
Wie bereits gesagt, nimmt der Konstruktor von A
zwei int
, während der Konstruktor von B
ein geordnetes Paar annimmt.
Sie können also
schreiben %Vor%oder
%Vor%oder
%Vor%aber Sie können nicht schreiben
%Vor%Darüber hinaus können Sie in Ihrem Mustervergleich den Inhalt von B weiterhin als zwei int definieren, aber Sie können den Inhalt von A nicht als Wert anordnen, der an ein geordnetes Paar gebunden ist
%Vor% Sie sind zwei verschiedene Arten. Die Interpretation dieser Syntax ist am Operator *
nicht eindeutig. Es kann in die Form reduziert werden:
type x = Y * Z
, in dem das '*' mit dem Schlüsselwort type
in OCaml verknüpft ist
oder
int * int
, in dem *
in der Kapazität eines Operators verwendet wird, der ein Tupel konstruiert
Die Standardpräzedenz nimmt es zu ersterem. Indem Sie eine Klammer um (int * int)
setzen, überschreiben Sie die Standardpriorität und erzwingen die letzte Interpretation.
Dies ist eines der kniffligen Dinge in der OCaml-Syntax - obwohl es aussieht, als würden Sie einen Konstruktor mit einem Tupeldatentyp ( A of int * int
) deklarieren, und selbst wenn Sie den Konstruktor verwenden, sieht es so aus, als wären Sie Geben Sie ein Tupel ( A (2,3)
), das ist eigentlich nicht was passiert.
Wenn Sie tatsächlich einen Tupel-Wert konstruieren und versuchen, ihn an den Konstruktor zu übergeben, wird er nicht kompiliert - let x = (2,3) in A x
. Stattdessen sind die *
in der Konstruktordefinition und die (,)
im Konstruktor use expression einfach die Syntax für einen Konstruktor von mehreren Argumenten . Die Syntax ahmt die eines Konstruktors mit einem Tupelargument nach, ist aber eigentlich getrennt. Die zusätzlichen Klammern sind erforderlich, wenn Sie einen Konstruktor mit einem einzelnen Tupelargument erstellen möchten.
Tags und Links ocaml