是否可以初始化函数引用的常量数组?
Is it possible to initialize a constant array of reference to function?
在阅读了 Embarcadero 关于 procedural types & anonymous methods and David Heffernan's explanation 的文档后,我仍然不太明白为什么编译器禁止初始化函数引用的常量数组,如下例中的 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$ActRec(CC8CF0) as TBar
Foo[0] := C_FOO[0]; // Foo[0] = MyProgram.FooBar
Bar[0] := C_FOO[0]; // Bar[0] = MyProgram$ActRec(CC8CF0) as TBar
end.
使用调试器,我可以看到 Bar[0] 等于某个地址(我想?),这告诉我我的理解背后发生了一些事情...
那么在我的例子中是否可以像C_BAR那样初始化一个常量数组?如果是,怎么做,否则,为什么?
相关文档位于 Typed Constants 部分:
Typed constants, unlike true constants, can hold values of array,
record, procedural, and pointer types. Typed constants cannot occur in
constant expressions.
Declare a typed constant like this:
const identifier: type = value
where identifier is any valid identifier, type is any type except
files and variants, and value is an expression of type. For example,
const Max: Integer = 100;
In most cases, value must be a constant expression; but if type is an
array, record, procedural, or pointer type, special rules apply.
程序类型的特殊规则如下:
To declare a procedural constant, specify the name of a function or
procedure that is compatible with the declared type of the constant.
For example,
function Calc(X, Y: Integer): Integer;
begin
...
end;
type TFunction = function(X, Y: Integer): Integer;
const MyFunction: TFunction = Calc;
Given these declarations, you can use the procedural constant
MyFunction in a function call:
I := MyFunction(5, 7)
You can also assign the value nil to a procedural constant.
这就解释了为什么可以使用 TFoo
声明类型常量。
至于匿名方法,它们没有在本文档的任何地方列出。现在,一个匿名方法被实现为一个接口。该接口有一个由编译器生成的支持 class,因此需要创建一个 class 的实例。该实例分配在堆上,这就是(至少一个原因)您不能将匿名方法声明为常量的原因。
在阅读了 Embarcadero 关于 procedural types & anonymous methods and David Heffernan's explanation 的文档后,我仍然不太明白为什么编译器禁止初始化函数引用的常量数组,如下例中的 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$ActRec(CC8CF0) as TBar
Foo[0] := C_FOO[0]; // Foo[0] = MyProgram.FooBar
Bar[0] := C_FOO[0]; // Bar[0] = MyProgram$ActRec(CC8CF0) as TBar
end.
使用调试器,我可以看到 Bar[0] 等于某个地址(我想?),这告诉我我的理解背后发生了一些事情...
那么在我的例子中是否可以像C_BAR那样初始化一个常量数组?如果是,怎么做,否则,为什么?
相关文档位于 Typed Constants 部分:
Typed constants, unlike true constants, can hold values of array, record, procedural, and pointer types. Typed constants cannot occur in constant expressions.
Declare a typed constant like this:
const identifier: type = value
where identifier is any valid identifier, type is any type except files and variants, and value is an expression of type. For example,
const Max: Integer = 100;
In most cases, value must be a constant expression; but if type is an array, record, procedural, or pointer type, special rules apply.
程序类型的特殊规则如下:
To declare a procedural constant, specify the name of a function or procedure that is compatible with the declared type of the constant. For example,
function Calc(X, Y: Integer): Integer; begin ... end; type TFunction = function(X, Y: Integer): Integer; const MyFunction: TFunction = Calc;
Given these declarations, you can use the procedural constant MyFunction in a function call:
I := MyFunction(5, 7)
You can also assign the value nil to a procedural constant.
这就解释了为什么可以使用 TFoo
声明类型常量。
至于匿名方法,它们没有在本文档的任何地方列出。现在,一个匿名方法被实现为一个接口。该接口有一个由编译器生成的支持 class,因此需要创建一个 class 的实例。该实例分配在堆上,这就是(至少一个原因)您不能将匿名方法声明为常量的原因。