Как различить вызов без аргументов и ссылку на функцию в назначении - PullRequest
5 голосов
/ 15 октября 2019

В присваивании, как я могу различить присваивание возвращаемого значения функции, которая не принимает параметров (и, следовательно, в вызове может не быть скобок), и присваивание самой ссылки на функцию. Только ли, глядя на тип принимающей переменной?

Вот фрагмент кода для иллюстрации (Delphi noob здесь):

type
   TIntFun = function():integer;
var
   IntFun : TIntFun;
   I : integer;
function AnIntFun(): integer;
begin
  result := 3;
end;
begin
  I := AnIntFun;  // argumentless call, returning 3
  IntFun := AnIntFun; // function assignment?
end

Ответы [ 2 ]

8 голосов
/ 15 октября 2019

Это только если посмотреть на тип принимающей переменной?

Да.

Это, на мой взгляд, веский аргумент против разрешения функцииСинтаксис вызова, чтобы опустить парены. Если бы этой языковой функции не существовало, вы должны были бы написать:

I := AnIntFun();
IntFun := AnIntFun;

Если бы вы были вынуждены написать ее таким образом, то компилятор будет рассматривать

I := AnIntFun; 

как синтаксисошибка. Выражение AnIntFun всегда будет иметь процедурный тип, и компилятору (и читателю) не нужно будет полагаться на контекст для определения типа выражения.

Использование контекста для определения типа выраженияочень нежелательно. Рассмотрим, например, перегрузку функций экземпляра:

procedure foo(fun: TIntFun); overload;
procedure foo(val: Integer); overload;

Когда вы пишете:

foo(AnIntFun);

Какую перегрузку вы считаете выбранной? Если язык требует паренсов при каждом вызове функции, тогда AnIntFun всегда имеет процедурный тип, и первая перегрузка будет выбрана без двусмысленности.

6 голосов
/ 15 октября 2019

Ваш код будет работать, как и ожидалось.

Но чтобы быть в явном виде, вы можете написать AnIntFun(), если вы хотите выполнить функцию, и @AnIntFun, если вы имеете в виду саму функцию.

program Project1;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils;

type
  TIntFcn = function: Integer;

procedure Test(Val: Integer); overload;
begin
  Writeln('Value: ' + Val.ToString);
end;

procedure Test(Fcn: TIntFcn); overload;
begin
  Writeln('Function. Returned value: ' + Fcn.ToString);
end;

function TestFcn: Integer;
begin
  Result := 3;
end;

begin
  Test(TestFcn()); // value (obvious)
  Test(@TestFcn); // fcn (obvious)
  Test(TestFcn); // value
  Readln;
end.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...