在此之后,在阅读关于procedural types和anonymous methods和David Heffernan's explanation的Embarcadero文档之后,我还是不太明白为什么编译器禁止初始化对函数的常量引用数组,例如在下面的示例中为C_BAR。
program MyProgram;
{$APPTYPE CONSOLE}
{$R *.res}
type
TFoo = function: Integer;
TBar = reference to function: Integer;
function FooBar: Integer;
begin
Result := 42;
end;
const
// This works
C_FOO: array[0..0] of TFoo = (FooBar);
// These lines do not compile
// C_BAR: array[0..0] of TBar = (FooBar); // TBar incompatible with Integer
// C_BAR: array[0..0] of TBar = (@FooBar); // TBar incompatible with Pointer
var
Foo: array[0..0] of TFoo;
Bar: array[0..0] of TBar;
begin
Foo[0] := FooBar; // Foo[0] = MyProgram.FooBar
Bar[0] := FooBar; // Bar[0] = MyProgram$1$ActRec($1CC8CF0) as TBar
Foo[0] := C_FOO[0]; // Foo[0] = MyProgram.FooBar
Bar[0] := C_FOO[0]; // Bar[0] = MyProgram$1$ActRec($1CC8CF0) as TBar
end.
使用调试器,我可以看到Bar [0]等于某个地址(我认为吗?),这表明我的理解背后正在发生某些事情……
那么在我的示例中是否可以初始化诸如C_BAR的常量数组?如果是,该怎么做,否则,为什么?
答案 0 :(得分:7)
相关文档在Typed Constants的部分中:
类型化常量与真实常量不同,可以保存数组的值, 记录,过程和指针类型。类型常量不能出现在 常量表达式。
声明这样的类型常量:
const identifier: type = value
其中,标识符是任何有效标识符,类型是除以下类型之外的任何类型 文件和变体,值是类型的表达。例如,
const Max: Integer = 100;
在大多数情况下,value必须是一个常量表达式;但是如果type是一个 数组,记录,过程或指针类型,需要应用特殊规则。
这些用于程序类型的特殊规则如下:
要声明过程常量,请指定函数名称或 与常量的声明类型兼容的过程。 例如,
function Calc(X, Y: Integer): Integer; begin ... end; type TFunction = function(X, Y: Integer): Integer; const MyFunction: TFunction = Calc;
鉴于这些声明,您可以使用过程常量 函数中的MyFunction:
I := MyFunction(5, 7)
您还可以将值nil分配给过程常量。
所以这解释了为什么可以使用TFoo
声明类型化的常量。
至于匿名方法,本文档未在任何地方列出它们。现在,匿名方法被实现为接口。该接口具有由编译器生成的后备类,因此需要创建该类的实例。该实例是在堆上分配的,这是(至少一个原因)为什么您不能将匿名方法声明为常量。