是否存在从Delphi中的内部函数访问外部函数Result变量的本机语法?

时间:2017-04-07 09:05:30

标签: delphi delphi-xe

考虑:

function OuterFunc: integer;
  function InnerFunc: integer;
  begin
    // Here I'd like to access the OuterFunc.Result variable
    // for both reading and writing its value
    OuterFunc.Result := OuterFunc.Result + 12;
  end;
begin
end;

是否有本机语法来访问InnerFunc中的OuterFunc Result变量?或者是唯一的方法来传递它像参数,如下所示?

function OuterFunc: integer;
  function InnerFunc(var outerResult: integer): integer;
  begin
  end;
var
  i: integer;
begin
  i := InnerFunc(Result);
end;

2 个答案:

答案 0 :(得分:11)

您可以通过分配函数名称将结果分配给函数,这实际上是Pascal中的原始方式:

function MyFunc: integer;
begin
  MyFunc := 2;
  // is equal to the following
  Result := 2;
end;

所以在你的情况下你可以写

function OuterFunc: integer;
  function InnerFunc: integer; 
  begin
    OuterFunc := 12;
  end;
begin
end;

请注意,在语句块中使用除了赋值运算符左侧之外的任何其他函数名称会导致递归调用,因此与预定义Result的工作方式不同。

换句话说,您无法从OuterFunc内访问之前设置的InnerFunc值。你需要使用例如在InnerFunc之前定义的外部作用域中的局部变量也可以从InnerFunc访问:

function OuterFunc: integer;
var
  OuterResult: integer;

  function InnerFunc: integer; 
  begin
    OuterResult := 0;
    OuterResult := OuterResult + 12;
  end;
begin
  Result := OuterResult;
end;

有关详细信息,请参阅the documentation中的Function Declarations

答案 1 :(得分:4)

除了使用本机Pascal语法(由Tom Brunberg的答案显示)之外,另一个选项是将本地函数转换为过程。

function OuterFunc: integer;
  procedure InnerFunc(out innerResult: integer); 
  begin
    {OuterFunc's} Result := 0;
    innerReuslt := -1;
  end;
var
  i: integer;
begin
  InnerFunc( i );
end;

由于这是你的INNER本地函数,你不会通过这个简单的更改破坏一些外部API /契约。

因为你的原始代码InnerFunc是事实上的程序,所以两次都没有使用它自己的Result,既不是调用者,也不是被调用者。

function OuterFunc: integer;
//  function InnerFunc: integer;
  procedure InnerFunc; 
  begin
    // here i'd like to access OuterFunc.Result variable
    // for both reading and writing its value
//    OuterFunc.Result := OuterFunc.Result + 12;
    Result := Result + 12;
  end;
begin
  InnerFunc();
end; 

但是好吧,我们假设您忘了使用BOTH功能的两个结果,但您最初打算这样做。 仍然有几种方法可以用来偷工减料并破解Delphi语言的意图 - 限制。

从该过程方法开始,如果要在表达式中使用此类函数,可以添加函数速记。 虽然它看起来有点难看并且为CPU添加了一个重定向调用(你不能内联本地函数,如果你的Delphi内联实现可能会遇到“寄存器跳舞”),那么有点慢下来(但取决于你在其他工作中称之为多少 - 额外的工作可能不明显)。

function OuterFunc: integer;
  procedure InnerFunc(out innerResult: integer); overload;
  begin
    innerResult := +2;
 //   {OuterFunc's} Result := Result + innerResult;
    Inc( Result, innerResult );
  end;
  function InnerFunc: integer; overload;
  begin
    InnerFunc( Result ); 
  end;
var
  i: integer;
begin
//  InnerFunc( i );
  i := InnerFunc();
end;

另一个黑客正在声明变量重叠。

function OuterFunc: integer;
var Outer_Result: integer absolute Result;
    i: integer;
  function InnerFunc: integer; 
  begin
    Result := +2;
    Inc( Outer_Result, Result );
  end;
begin
  i := InnerFunc();
end;

现在,这种方法可能会破坏优化,例如将“结果”放在CPU寄存器中,强制使用RAM,这样会慢一些。 此外,一旦您可能希望更改OuterFunc的类型,并且如果您忘记更改Outer_Result var的类型 - 您自己搞砸了。

function OuterFunc: double; // was - integer; Proved to be not enough since 2020
var Outer_Result: integer absolute Result;  // and here we forgot to sync type changing.... ooooops!
    i: integer;
  function InnerFunc: integer; 
....

表达这种意图的不那么强硬的方式(以分配和访问另外一个RAM内变量为代价)将是这样的:

function OuterFunc: integer;
{$T+} // we need to enable type checking: predictability is safety
var Outer_Result: ^integer;
    i: integer;
  function InnerFunc: integer; 
  begin
    Result := +2;
    Inc( Outer_Result^, Result );
  end;
begin
  Outer_Result := @Result;
  i := InnerFunc();
end;

但是所有这些选择都是黑客攻击,打破了概念清晰度,从而妨碍了人们在未来阅读/理解程序的能力。 如果您需要变量 - 那么请声明变量。这将是最明确的选择。毕业程序更多是为未来的程序员编写的,而不是计算机编译它们。 : - )

function OuterFunc: integer;
var the_Outer_Result: integer;
  function InnerFunc; 
  begin
    Result := +2;
    Inc( the_Outer_Result, Result );
  end;
var
  i: integer;
begin
  the_Outer_Result := 0;

  .....
    I := InnerFunc();
  .....

  Result := the_Outer_Result;
end;

这样你就不会与语言作斗争,但是放弃并按照预期的方式使用它。战斗和超越语言总是很有趣,但从长远来看,当你必须维护5年前人类最后阅读的代码并将其移植到更新版本的Delphi / libraries / Windows时 - 那么非自然智能技巧往往会变得很烦人。