一个函数正在返回一个匿名函数。我想将结果分配给变量。但是编译器认为我正在尝试分配函数而不是函数的结果。我该如何解决这个问题?
program Project9;
{$APPTYPE CONSOLE}
type
TMyEvent = reference to function: string;
var
v1: TMyEvent;
function GetHandler: TMyEvent;
begin
Result := function: string
begin
Result := '';
end;
end;
begin
v1 := GetHandler; // <- Incompatible types: 'TMyEvent' and 'Procedure'
end.
注意:我确实有一个解决方法,但我希望在不引入包装器的情况下解决这个问题:
program Project9;
{$APPTYPE CONSOLE}
type
TMyEvent = reference to function: string;
TWrapper = record
FHandler: TMyEvent;
end;
var
v1: TMyEvent;
function GetHandler: TWrapper;
begin
Result.FHandler := function: string
begin
Result := '';
end;
end;
begin
v1 := GetHandler.FHandler; // <- works
编辑:这不是特定于匿名或任何特殊类型的函数:对于返回函数的任何函数来说都是实际的,在第一个Delphi到达之前在Turbo Pascal中也是如此。 < / p>
答案 0 :(得分:18)
如果您的匿名方法/函数是无框架的,则必须使用();
进行分配v1 := GetHandler();
如果没有括号,Delphi会尝试将函数赋给变量。括号告诉它将函数结果赋给变量。
答案 1 :(得分:6)
Delphi的函数调用语法与大多数其他语言略有不同。在大多数语言中,为了调用函数,必须在函数名后使用parens ()
,通常称为函数调用运算符。如果函数只是简单命名,并且没有提供任何parens,那么该表达式将在不调用调用的情况下计算函数。
因此,以C ++语言为例,
i = foo();
调用该函数并将返回值存储在i
。
另一方面,
fn = foo;
将函数的地址存储在函数指针变量fn
中。
Delphi与此不同,对于无参数功能,允许您省略parens,但仍然调用该函数。所以在Delphi中,上面的第一行代码可以写成
i := foo;
这将调用该函数。
如果函数返回类型是过程类型,方法或匿名方法,那么它会变得有点棘手。
在您的方案中,
v1 := GetHandler;
在编译器的眼中是模棱两可的。因为v1
是一个类型是匿名方法的变量,所以编译器在省略parens时永远不会生成调用。如果它确实生成了一个调用,那么你将无法将一个函数简单地赋值给一个过程类型变量。
因此编译器会切换到您在C ++等语言中找到的行为。如果您希望调用该函数,则必须提供parens。要使代码编译和工作,请编写
v1 := GetHandler();
documentation详细介绍了该问题。关键摘录如下:
在赋值语句中,左侧变量的类型决定了右侧过程或方法指针的解释。
现在,在判决中,我发现表达式的上下文可以确定其解释是相当令人不安的。这一切都源于允许在省略parens时进行函数调用。我宁愿总是使用parens,所以避免上面讨论的歧义。特别是这将允许表达意义独立于上下文。
要明白我的意思,我们回到原来的例子。现在让我们更具体地说明所涉及的类型:
type
TIntFunc = function: Integer;
function foo: Integer;
begin
Result := 42;
end;
var
i: Integer;
fn: TIntFunc;
此时我们可以写:
i := foo; // i is an integer, so the function is called
fn := foo; // fn is a procedural type variable, so the function is not called
我个人觉得这种情况根本不令人满意。