Может кто-нибудь объяснить мне анонимные методы?

StackOverflow https://stackoverflow.com/questions/256146

Вопрос

Delphi 2009, среди некоторых интересных вещей, также только что получил анонимные методы. Я видел примеры и посты в блоге, касающиеся анонимных методов, но пока не получил их. Может кто-нибудь объяснить, почему я должен быть взволнован?

Это было полезно?

Решение

Подумайте о типичном коде обратного вызова, в котором вам нужны данные, доступные для обратного вызова. Зачастую эти данные необходимы для обратного вызова только , но вам нужно перепрыгнуть через несколько обручей, чтобы получить их, не прибегая к методам, не подходящим для ООП, таким как глобальные переменные. С помощью анонимных методов данные могут оставаться там, где они есть - вам не нужно излишне расширять область действия или копировать их в какой-то вспомогательный объект. Просто напишите свой код обратного вызова на месте как анонимный метод, и он сможет полностью получить доступ и манипулировать всеми локальными переменными на сайте, где определен анонимный метод (а не там, где он вызывается!).

Существуют и другие аспекты анонимных методов, наиболее очевидным из которых является то, что они, ну, в общем-то, анонимные, но именно они действительно заставили их пойти " нажмите " для меня ...

Другие советы

Посмотрите крышки .

Анонимные функции Delphi являются замыканиями.

Они создаются в других функциях и поэтому имеют доступ к области действия этой функции. Это даже в том случае, если анонимная функция назначается параметру функции, который вызывается после вызова исходной функции. (Я создам пример через минуту).

type
  TAnonFunc = reference to procedure;
  TForm2 = class(TForm)
    Memo1: TMemo;
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
  private
    F1 : TAnonFunc;
    F2 : TAnonFunc;
  end;

procedure TForm2.Button1Click(Sender: TObject);
var
  a : Integer;
begin
  a := 1;

  F1 := procedure
  begin
    a := a + 1;
  end;

  F2 := procedure
  begin
    Memo1.Lines.Add(IntToStr(a));
  end;
end;

Приведенный выше метод назначает две анонимные функции полям F1 и F2. Первый увеличивает локальную переменную, а второй показывает значение переменной.

procedure TForm2.Button2Click(Sender: TObject);
begin
  F1;
end;

procedure TForm2.Button3Click(Sender: TObject);
begin
  F2;
end;

Теперь вы можете вызывать обе функции, и они получают доступ к одному и тому же. Поэтому, если дважды вызвать F1, а F2 - 3. Конечно, это простой пример. Но его можно расширить до более полезного кода.

В многопоточной среде анонимные функции могут использоваться при вызове Synchronize, что устраняет необходимость в бесчисленных методах.

Может быть, этот пример может быть для вас полезным. Здесь я собираюсь реализовать масштабируемый список отображения для рисования на TCanvas без объявления различных типов классов отображения. Это также интенсивно использует Дженерики. Предположим, у нас есть TForm с TPaintBox и TTrackBar на нем ...

type
  TDisplayProc = TProc<TCanvas>;

type
  TFrmExample3 = class(TForm)
    pbxMain: TPaintBox;
    trkZoom: TTrackBar;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure pbxMainClick(Sender: TObject);
    procedure pbxMainMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
    procedure pbxMainPaint(Sender: TObject);
    procedure trkZoomChange(Sender: TObject);
  private
    FDisplayList: TList<TDisplayProc>;
    FMouseX: Integer;
    FMouseY: Integer;
    FZoom: Extended;
    procedure SetZoom(const Value: Extended);
  protected
    procedure CreateCircle(X, Y: Integer);
    procedure CreateRectangle(X, Y: Integer);
    function MakeRect(X, Y, R: Integer): TRect;
  public
    property Zoom: Extended read FZoom write SetZoom;
  end;

implementation

{$R *.dfm}

procedure TFrmExample3.PaintBox1Paint(Sender: TObject);
var
  displayProc: TDisplayProc;
begin
  for displayProc in FDisplayList do
    displayProc((Sender as TPaintBox).Canvas);
end;

procedure TFrmExample3.CreateCircle(X, Y: Integer);
begin
  FDisplayList.Add(
    procedure (Canvas: TCanvas)
    begin
      Canvas.Brush.Color := clYellow;
      Canvas.Ellipse(MakeRect(X, Y, 20));
    end
  );
end;

procedure TFrmExample3.CreateRectangle(X, Y: Integer);
begin
  FDisplayList.Add(
    procedure (Canvas: TCanvas)
    begin
      Canvas.Brush.Color := clBlue;
      Canvas.FillRect(MakeRect(X, Y, 20));
    end
  );
end;

procedure TFrmExample3.FormCreate(Sender: TObject);
begin
  FDisplayList := TList<TDisplayProc>.Create;
end;

procedure TFrmExample3.FormDestroy(Sender: TObject);
begin
  FreeAndNil(FDisplayList);
end;

function TFrmExample3.MakeRect(X, Y, R: Integer): TRect;
begin
  Result := Rect(Round(Zoom*(X - R)), Round(Zoom*(Y - R)), Round(Zoom*(X + R)), Round(Zoom*(Y + R)));
end;

procedure TFrmExample3.pbxMainClick(Sender: TObject);
begin
  case Random(2) of
    0: CreateRectangle(Round(FMouseX/Zoom), Round(FMouseY/Zoom));
    1: CreateCircle(Round(FMouseX/Zoom), Round(FMouseY/Zoom));
  end;
  pbxMain.Invalidate;
end;

procedure TFrmExample3.pbxMainMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
begin
  FMouseX := X;
  FMouseY := Y;
end;

procedure TFrmExample4.SetZoom(const Value: Extended);
begin
  FZoom := Value;
  trkZoom.Position := Round(2*(FZoom - 1));
end;

procedure TFrmExample4.trkZoomChange(Sender: TObject);
begin
  Zoom := 0.5*(Sender as TTrackBar).Position + 1;
  pbxMain.Invalidate;
end;

Люди уже предоставили код, поэтому я просто перечислю несколько мест, где они могут быть полезны.

Скажем, у вас есть некоторый код GUI. Обычно, для чего-то вроде обработчика нажатия кнопки, вы должны предоставить функцию, которая будет вызываться при нажатии этой кнопки. Однако, скажем, все, что должна делать эта функция, это что-то простое, например, всплывающее окно с сообщением или какое-то поле. Допустим, у вас есть десятки этих кнопок в вашем коде. Без анонимных функций у вас будет множество функций, называемых «OnButton1Click», " & Quot; OnExitButtonClick, & Quot; и т. д., что может загромождать ваш код ... или вы можете создавать анонимные функции, которые немедленно присоединяются к этим событиям, и вам больше не нужно о них беспокоиться.

Другое использование - функциональное программирование. Скажем, у вас есть список номеров. Вы хотите вернуть только те числа, которые делятся на три. Вероятно, существует функция с именем filter , которая принимает функцию, которая возвращает логическое значение и список, и возвращает новый список, содержащий только те элементы в первом списке, которые при передаче в функцию возвращали значение True. Пример:

filter(isOdd, [1, 2, 3, 5, 6, 9, 10]) --> [1, 3, 5, 9]

Было бы раздражающим быть вынужденным определять функцию "isDivisibleByThree", а затем передавать ее в фильтр, так что другим использованием анонимных функций здесь было бы просто быстро создать функцию, которая вам больше нигде не нужна, и передать это фильтровать.

Я отвечаю на свой вопрос, но нашел хорошее объяснение анонимных методов здесь Может ли ваш язык программирования сделать это?

Полагаю (я не знаю Delphi), это означает, что вы можете создавать функции как объект данных. Это означает, что вы можете, например, передавать функции в качестве параметров другим функциям. Пример: функция сортировки может принимать функцию сравнения в качестве параметра, что делает ее более универсальной.

Анонимные методы полезны в функциональном программировании, но они также могут помочь вам написать более компактный код в структурированном программировании. Потоки, например: http://blogs.codegear.com/abauer/2008 / 09/08/38868

Еще один вариант использования вашего «возбуждения» :): http://delphi.fosdal.com/2008/08/anonymous-methods-when-to-use-them.html

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top