如何将由另一个函数返回的函数赋值给函数变量?结果而不是生成函数本身

时间:2014-01-20 23:05:32

标签: function delphi variables function-pointers anonymous-methods

一个函数正在返回一个匿名函数。我想将结果分配给变量。但是编译器认为我正在尝试分配函数而不是函数的结果。我该如何解决这个问题?

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>

2 个答案:

答案 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

我个人觉得这种情况根本不令人满意。