В чем разница между
TFuncOfIntToString = reference to function(x: Integer): string;
и
TFuncOfIntToString = function(x: Integer): string of object;
Я использую объект
В чем разница между
TFuncOfIntToString = reference to function(x: Integer): string;
и
TFuncOfIntToString = function(x: Integer): string of object;
Я использую объект
Рассмотрим следующие три объявления типа:
TProcedure = procedure;
TMethod = procedure of object;
TAnonMethod = reference to procedure;
Все они очень похожи друг на друга. Что касается вызова экземпляров каждого из этих трех типов, вызывающий код идентичен. Различия возникают в том, что может быть присвоено переменным этих типов.
Процедурные типы
TProcedure
является процедурным типом. Вы можете назначить переменной типа TProcedure
что-то из этой формы:
procedure MyProcedure;
begin
end;
Это не объектно-ориентированная процедура. Вы не можете назначить метод экземпляра или класса переменной TProcedure
. Тем не менее, вы можете назначить метод переменной TProcedure
.
Указатели методов
TMethod
является указателем метода . Об этом свидетельствует наличие of object
. Когда у вас есть переменная типа TMethod
, вы должны назначить либо:
Таким образом, вы можете назначить любое из них:
procedure TMyClass.MyMethod;
begin
end;
class procedure TMyClass.MyClassMethod;
begin
end;
Большая разница между процедурным типом и указателем метода заключается в том, что последний содержит ссылку на код и данные. Указатель метода часто известен как процедурный тип с двумя указателями. Переменная, содержащая указатель метода, содержит ссылки на код и экземпляр/класс для его вызова.
Рассмотрим следующий код:
var
instance1, instance2: TMyClass;
method1, method2: TMethod;
....
method1 := instance1.MyMethod;
method2 := instance2.MyMethod;
Теперь, хотя method1
и method2
относятся к одному и тому же фрагменту кода, они связаны с разными экземплярами объектов. Итак, если мы будем называть
method1();
method2();
Мы вызываем MyMethod
в двух разных экземплярах. Этот код эквивалентен:
instance1.MyMethod();
instance2.MyMethod();
Анонимные методы
Наконец, мы переходим к анонимным методам. Это еще более общая цель, чем процедурные типы и указатели методов. Вы можете назначить любое из следующих значений переменной, определенной с помощью синтаксиса reference to
:
Например:
var
AnonMethod: TAnonMethod;
....
AnonMethod := MyProcedure; // item 1 above
AnonMethod := instance1.MyMethod; // item 2
AnonMethod := TMyClass.MyClassMethod; // item 3
Анонимные методы, пункт 4 выше, являются объявленными в строке в вашем коде. Например:
var
AnonMethod: TAnonMethod;
....
AnonMethod := procedure
begin
DoSomething;
end;
Самое большое преимущество анонимных методов по сравнению с процедурными типами и указателями методов заключается в том, что они позволяют захват переменных. Например, рассмотрим следующую короткую программу для иллюстрации:
{$APPTYPE CONSOLE}
program VariableCapture;
type
TMyFunc = reference to function(X: Integer): Integer;
function MakeFunc(Y: Integer): TMyFunc;
begin
Result := function(X: Integer): Integer
begin
Result := X*Y;
end;
end;
var
func1, func2: TMyFunc;
begin
func1 := MakeFunc(3);
func2 := MakeFunc(-42);
Writeln(func1(4));
Writeln(func2(2));
Readln;
end.
Это имеет следующий результат:
12 -84
Первый - анонимный метод, второй - обычный method.