5

考虑以下程序:

{$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.

输出是:

2
0
---
0
2
---

为什么两个循环产生不同的输出?

4

3 回答 3

4

因为数组包含订单信息,而集合不包含。


使用文档进行说明:

静态或动态数组的内部数据格式

存储为数组组件类型的连续元素序列。具有最低索引的组件存储在最低的内存地址。

for in循环遍历这些索引是按增量顺序完成的

数组按递增顺序遍历,从最低数组边界开始,到数组大小减一结束。

另一方面,集合的内部数据格式

是一个位数组,其中每个位表示一个元素是否在集合中。

因此,所有这些“指示位”都存储在一个相同的“值”中。这就是为什么可以将集合类型转换为 Integer 类型,以及为什么添加位的顺序会丢失:[enum3, enum1] = [enum1, enum3].

于 2015-06-29T17:36:49.660 回答
3
for Enum in Arr do
  Writeln(ord(Enum));

这里,Arr是一个数组,所以数组中的项是按顺序输出的。文档说:

数组按递增顺序遍历。

因此2是之前的输出0

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

这里,[enum3, enum1]是一个集合,集合的枚举数恰好按序数值递增的顺序进行枚举。所以输出是0第一位的。

我认为文档中的任何地方都没有说明按该顺序枚举集合,但从经验上看似乎是这样。但是,由于集合是一种无序类型,因此无论如何都不应该依赖它们的枚举顺序。


所以问题就变成了理解如何[...]在代码的不同点成为集合或数组。这一切都源于新的 XE7 动态数组语法,它引入了(另一种)语法歧义。当我们写

Arr := [enum3, enum1];

然后[enum3, enum1]是一个数组。编译器知道这Arr是一个数组,并且该信息定义了文字的类型。

但是当我们写

for Enum in [enum3, enum1] do

然后[enum3, enum1]是一组。这里的文字原则上可以是数组或集合。在这种情况下,我相信编译器总是更喜欢集合。

同样,我找不到任何说明情况如此的文档,但根据经验,情况确实如此。大概是因为集合枚举器早于新的动态数组语法,所以当有歧义时它们优先。

形式文字的含义[...]取决于其上下文。

于 2015-06-29T14:34:11.977 回答
1

虽然并不总是理想的,但编译器使用上下文来确定右侧的类型。您可以将字符串视为一个很好的例子:

如果 constantExpression 是字符串,则声明的常量与任何字符串类型兼容。如果字符串的长度为 1,则它也兼容任何字符类型。

在字符串的情况下,编译器将使用左侧来确定右侧的类型。这与问题中的代码之间的区别在于,此案例已明确记录,而问题中的案例则没有。

使用字符的示例:

{$APPTYPE CONSOLE}

uses
  SysUtils, Classes;

var
  A: Char;
  B: AnsiChar;

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

  Writeln(A);
  Writeln(B);

  Readln;
end.

从两者生成的汇编程序表明,在这两种情况下,右手边的处理方式不同:

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

编译器正在使用赋值的目标类型来确定字符串(在本例中为“a”)应该是什么类型。问题中也发生了类似的事情。

感谢大卫在评论中提供更多信息

于 2015-06-29T18:12:06.110 回答