2015-06-29 7 views
5

Betrachten Sie das folgende Programm:Warum haben Literale der Form [...] Bedeutung, die vom Kontext abhängt?

{$APPTYPE CONSOLE} 

type 
    TMyEnum = (enum1, enum2, enum3); 

var 
    Arr: TArray<TMyEnum>; 
    Enum: TMyEnum; 

begin 
    Arr := [enum3, enum1]; // <-- this is an array 
    for Enum in Arr do 
    Writeln(ord(Enum)); 
    Writeln('---'); 

    for Enum in [enum3, enum1] do // <-- this looks very much like the array above 
    Writeln(ord(Enum)); 
    Writeln('---'); 

    Readln; 
end. 

Die Ausgabe lautet:

 
2 
0 
--- 
0 
2 
--- 

Warum die beiden Schleifen unterschiedlich ausfallen?

Antwort

3
for Enum in Arr do 
    Writeln(ord(Enum)); 

Hier Arr ist ein Array, und so die Elemente des Arrays werden ausgegeben, um. Die documentation sagt:

das Array in ansteigender Reihenfolge durchquert wird.

Daher wird 2 vor 0 ausgegeben.

for Enum in [enum3, enum1] do 
    Writeln(ord(Enum)); 

Hier [enum3, enum1] ist ein Satz und der Enumerator für einen Satz geschieht in der Reihenfolge zunehmender Ordnungswert aufzuzählen. Also hat die Ausgabe zuerst 0.

Ich glaube nicht, dass irgendwo in der Dokumentation angegeben ist, dass Mengen in dieser Reihenfolge aufgelistet sind, aber empirisch scheint das der Fall zu sein. Da die Mengen jedoch ungeordnet sind, sollte man sich nicht auf ihre Aufzählungsreihenfolge verlassen.


Also die Frage ist dann zu verstehen, wie [...] ein Satz sein kann oder ein Array an verschiedenen Stellen im Code. Dies alles stammt aus der neuen dynamischen Syntax des XE7-Arrays, die (eine weitere) syntaktische Mehrdeutigkeit einführt. Wenn wir

Arr := [enum3, enum1]; 

schreiben dann ist [enum3, enum1] ein Array. Der Compiler weiß, dass Arr ein Array ist und diese Information den Typ des Literals definiert.

Aber wenn wir

for Enum in [enum3, enum1] do 

schreiben dann ist [enum3, enum1] ein Satz. Hier könnte das Literal im Prinzip entweder Array oder Set sein. In solchen Situationen glaube ich, dass der Compiler Sätze immer bevorzugen wird.

Wieder kann ich keine Dokumentation finden, die besagt, dass dies so ist, aber empirisch ist dies der Fall. Vermutlich da die gesetzten Enumeratoren die neue dynamische Array-Syntax vordatieren, haben sie Vorrang, wenn eine Mehrdeutigkeit vorliegt.

Die Bedeutung eines Literals der Form [...] hängt von seinem Kontext ab.

+0

Im Allgemeinen, bis die neue Syntax für dynarrays um kam (XE7 oder 8?), '[]' War immer ein Satz. Erst nachdem der neue Synatx eingeführt wurde, konnten Dynarrays mit '[]' Syntax initialisiert werden. In der Tat, Arr ist ein Array (was sonst?), Während das allgemeine wörtliche '[...]' hat immer eine Menge bezeichnet, da die guten alten Pascal Tage.So gibt es nichts Seltsames daran, IMO. Aufzählungszeichen haben nicht notwendigerweise eine spezielle Reihenfolge, aber IIRC wurde irgendwo erwähnt, dass Mengen in zunehmender Ordnungszahl aufgezählt werden. –

+0

@Rudy Können Sie eine Dokumentationsverknüpfung für Sets bereitstellen, die in aufsteigender Ordnung aufgelistet werden? –

+0

@Rudy Wie für * literal '[...]' hat immer eine Menge * bezeichnet, nun, das ist nicht mehr wahr. Es scheint eine Menge zu sein, außer es ist ein Array. Es hängt vom Kontext ab. Ich kann keine Dokumentation dafür finden. Es wäre großartig, wenn du es ausgraben könntest. –

3

Weil ein Array Bestellinformationen enthält und ein Set nicht.


Erläuterung mit der Verwendung von Dokumentation:

Die internal data format einen statischen oder dynamischen Array:

als eine zusammenhängende Folge von Elementen des Komponententypen des Arrays gespeichert ist, . Die Komponenten mit den niedrigsten Indizes werden an den niedrigsten Speicheradressen gespeichert.

Fuß über diesen Indizes mit einer for in Schleife is done in incremental order:

Das Array wird in ansteigender Reihenfolge durchquert, an der tiefstenen Arrays gebunden und endend an der Feldgrße minus eins.

Auf der anderen Seite ist die internal data format ein gesetzt:

ein Bit-Array ist, wobei jedes Bit anzeigt, ob ein Element in der Gruppe ist oder nicht.

Somit werden alle diese "angezeigten Bits" in ein und demselben "Wert" gespeichert. Deshalb kann ein Satz typecasted to an Integer type sein, und warum die Reihenfolge, in der die Bits hinzugefügt werden, verloren ist: [enum3, enum1] = [enum1, enum3].

+0

Ich nehme an, ich wunderte mich mehr darüber, warum '[...]' manchmal ein Array war und ein Set zu anderen Zeiten. Ich hätte das deutlicher machen sollen. –

+0

Dann wäre die Antwort: Da der Kontext durch die Deklaration der Typen bestimmt wird, ist es die Sprache. ;) – NGLN

+0

Das war was ich wirklich gefahren bin. Und natürlich wusste ich die Antwort, als ich die Frage stellte. Wenn ich irgendwelche Dokumentation verpasst habe, die das erklärt, dann wäre das schön zu sehen.+1 –

1

Obwohl nicht immer ideal, verwendet der Compiler Kontext, um den Typ der rechten Seite zu bestimmen. Sie können als ein gutes Beispiel dafür an Zeichenkette suchen:

If constantExpression is a character string, the declared constant is compatible with any string type. If the character string is of length 1, it is also compatible with any character type.

In dem Zeichenkette Fall wird der Compiler Auf die linke Seite verwenden, um die Art von der rechten Seite zu bestimmen. Der Unterschied zwischen diesem und dem Code in der Frage ist, dass dieser Fall eindeutig dokumentiert ist, während der Fall in der Frage nicht ist.

Ein Beispiel unter Verwendung von Zeichen:

{$APPTYPE CONSOLE} 

uses 
    SysUtils, Classes; 

var 
    A: Char; 
    B: AnsiChar; 

begin 
    A := 'a'; 
    B := 'a'; 

    Writeln(A); 
    Writeln(B); 

    Readln; 
end. 

Der Assembler aus den beiden erzeugt wird, zeigt, dass die rechte Seite unterschiedlich in den beiden Fällen behandelt wird:

Project10.dpr.17: A := 'a'; 
004D6731 66C705C8034E006100 mov word ptr [$004e03c8],$0061 
Project10.dpr.18: B := 'a'; 
004D673A C605CA034E0061 mov byte ptr [$004e03ca],$61 

der Compiler das Ziel wird mit Typ der Zuweisung, um zu bestimmen, welcher Typ die Zeichenfolge (in diesem Fall 'a') sein sollte. Ähnliches passiert in der Frage.

Dank David für die zusätzliche Informationen in den Kommentaren

+0

Was Sie sagen, ist im Allgemeinen wahr, aber das Beispiel ist nicht zwingend. Es ist durchaus möglich, dass "1" eine ganze Zahl ist und der Compiler diesen Code in der Zuweisung zum Fließkommatyp ausgibt. Das ist eine vollkommen akzeptable Typ-Promotion, die der Compiler zur Kompilierzeit ausführen kann. Sie würden 'MyReal: = MyInt' glücklich schreiben und nicht davon ausgehen, dass' MyInt' ein echter Typ sein muss. Sie würden sich sehr freuen, wenn die Werbeaktion zur Laufzeit ausgeführt wird. –

+0

Die Dokumente unterstützen dies: http://docwiki.embarcadero.com/RADStudio/en/Fundamental_Syntactic_Elements#Numerals * Zahlen mit Dezimalpunkten oder Exponenten bezeichnen Reellen, während andere Zahlen ganze Zahlen bezeichnen. * –

+0

@DavidHeffernan Ok, geändert, um a zu verwenden besseres Beispiel. Ich stimme dir zu, Int und Single war ein schlechtes Beispiel. – Graymatter

Verwandte Themen