#delphi #anonymous-types #delphi-10.4-sydney
#delphi #анонимные типы #delphi-10.4-сидней
Вопрос:
Читая документацию по анонимным методам в Delphi, я начал задаваться вопросом. Я всегда использовал что-то вроде этого:
type TMathFn = Function(A, B: Integer): Integer;
var fn: TMathFn;
У меня всегда получалось. Но этот документ говорит мне использовать это вместо:
type TMathFn = Reference to Function(A, B: Integer): Integer;
var fn: TMathFn;
И поскольку я разрабатывал в Delphi с 1994 по 2010 год, я немного незнаком с этой частью «Ссылки на». Тем не менее, оба варианта, похоже, работают одинаково. Итак…
Они идентичны?
Ответ №1:
«ССЫЛКА НА» предназначена для разрешения анонимных методов (встроенных определений процедур / функций), которые могут захватывать контекст (например, локальные переменные, которые записываются как ссылки, т. Е.. если вы измените переменную после захвата, будет записано измененное значение, см. Ниже).
TYPE TMyProc = REFERENCE TO PROCEDURE(CONST S : STRING);
PROCEDURE Information(CONST S : STRING);
BEGIN
MessageDlg(S,mtInformation,[mbOK],0)
END;
PROCEDURE RunProc(P : TMyProc ; CONST S : STRING);
BEGIN
P(S)
END;
PROCEDURE A(B,C : INTEGER);
VAR
D : INTEGER;
P : TMyProc;
BEGIN
D:=3;
// D is 3 at the time of capture
P:=PROCEDURE(CONST S : STRING)
BEGIN
Information(S ': ' IntToStr(D) ' -> ' IntToStr(B))
END;
// D is now 4 - and is reflected in the captured routine, as
// the capture is done by REFERENCE and not by VALUE.
INC(D);
RunProc(P,'Hello')
END;
BEGIN
A(2,3)
END.
В окне сообщения отобразится «Привет: 4 -> 2».
Приведенное выше определение P «захватывает» (включает) переменные D и B, так что даже если вы передадите его другой функции, где эти переменные не существуют, вы все равно сможете получить к ним доступ.
Это было бы (почти) невозможно сделать с обычными процедурами [объектных] типов, поскольку они не могут получить доступ к локальным переменным, объявленным в момент выполнения.
Комментарии:
1. Для меня достаточно ясно. Поскольку мне просто нужны указатели на функции, я могу пропустить «ссылку на». Как я и подозревал. 🙂
2. Небольшая проблема. Захват не состояния, а переменных. Состояние обычно подразумевает, что фиксируются значения, но фиксируются переменные.
3. @DavidHeffernan: Хороший момент — я соответствующим образом обновил ответ…
4. Это чрезмерное (и смешанное) использование ВСЕХ заглавных букв заставляет меня рвать на себе волосы…
5. @JerryDodge: Тогда отвернись — мы не можем допустить, чтобы ты облысел 🙂
Ответ №2:
Нет, они не идентичны.
Разница в том, что
TMathFn = function(A, B: Integer): Integer;
это обычная функция,
TMathMethod = function(A, B: Integer): Integer of object;
это метод, и
TMathAnonMethod = reference to function(A, B: Integer): Integer;
это анонимный метод, но вы также можете назначить обычную функцию или метод переменной этого типа.
Так, например, если
type
TMathFn = function(A, B: Integer): Integer;
TMathMethod = function(A, B: Integer): Integer of object;
TMathAnonMethod = reference to function(A, B: Integer): Integer;
function Test(A, B: Integer): Integer;
begin
Result := A B;
end;
type
TTestClass = class
function Test(A, B: Integer): Integer;
end;
{ TTestClass }
function TTestClass.Test(A, B: Integer): Integer;
begin
Result := A B;
end;
тогда применяется следующее:
procedure TForm1.FormCreate(Sender: TObject);
var
T: TTestClass;
F: TMathFn;
M: TMathMethod;
AM: TMathAnonMethod;
begin
T := TTestClass.Create;
try
F := Test; // compiles
F := T.Test; // doesn't compile
F := function(A, B: Integer): Integer
begin
Result := A B;
end; // doesn't compile
M := Test; // doesn't compile
M := T.Test; // compiles
M := function(A, B: Integer): Integer
begin
Result := A B;
end; // doesn't compile
AM := Test; // compiles
AM := T.Test; // compiles
AM := function(A, B: Integer): Integer
begin
Result := A B;
end; // compiles
finally
T.Free;
end;
end;
Под капотом, как вы, наверное, уже знаете, F
это просто указатель (на функцию) и M
указатель на метод. Анонимные методы, с другой стороны, имеют более сложную реализацию на основе интерфейса, которая позволяет использовать всю их магию (например, захват переменных).
Комментарии:
1. ГОРАЗДО лучшее и более полезное объяснение, чем принятый ответ. Интересно, есть ли какой-либо недостаток в обычном использовании «ссылки на» (не то, чтобы я рассматривал возможность этого).
2. @stackmik: Возможно, самым важным недостатком
reference to
является снижение производительности. У всей его магии есть цена. В подавляющем большинстве приложений это незначительно (потому что компьютеры сегодня действительно быстры), но в критически важных для производительности частях дополнительные затраты на самом деле весьма заметны.3. И вам также нужны обычные типы процедур, когда вы взаимодействуете с API, такими как Windows API. (Например, используя функции из DLL, процедуры обратного вызова.)