代码之家  ›  专栏  ›  技术社区  ›  Steve

有人能给我解释一下匿名方法吗?

  •  28
  • Steve  · 技术社区  · 17 年前

    Delphi2009,在一些很酷的东西中,也有一些匿名方法。我已经看过这些例子,以及关于匿名方法的博客文章,但我还没有得到它们。有人能解释为什么我会兴奋吗?

    7 回复  |  直到 17 年前
        1
  •  16
  •   Toon Krijthe    17 年前

    请看一看 closures .

    这些是在其他函数中创建的,因此可以访问该函数的范围。即使将异常函数指定给在调用原始函数后调用的函数参数,情况也是如此。(稍后我将创建一个示例)。

    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;
    

    现在可以调用这两个函数,它们访问相同的a。因此,两次调用F1和一次调用F2显示为3。 当然,这是一个简单的例子。但它可以扩展为更有用的代码。

    在多线程环境中,可以在调用同步时使用匿名函数,从而消除了对无数方法的需要。

        2
  •  12
  •   Oliver Giesen    17 年前

    试想一下典型的回调代码,其中需要有回调可用的数据。回调通常需要这些数据 只有

    匿名方法还有其他方面,最明显的事实是,它们是匿名的,但这正是让它们为我“点击”的原因。。。

        3
  •  11
  •   Uwe Raabe    17 年前

    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;
    
        4
  •  5
  •   Claudiu    17 年前

    人们已经提供了代码,所以我只列出一些它们有用的地方。

    假设您有一些GUI代码。通常,对于按钮的onclick处理程序,您必须提供一个在单击该按钮时调用的函数。但是,假设该函数只需要做一些简单的事情,比如弹出一个消息框或在某处设置一个字段。假设在代码中有几十个这样的按钮。如果没有匿名函数,您将不得不拥有大量名为“OnButton1Click”、“OnExitButtonClick”等的函数,这些函数可能会使代码变得混乱。。。或者,您可以创建立即附加到这些事件的匿名函数,而不必再担心它们。

    另一个用途是函数式编程。假设你有一个数字列表。你只想得到那些可以被3整除的数字。可能有一个函数名为 filter 它接受一个返回布尔值和列表的函数,并返回一个新列表,该列表仅包含第一个列表中传递给函数时返回True的元素。例子:

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

    被迫定义一个函数“IsDivisible By Three”,然后将其传递给filter,这会很烦人,因此匿名函数的另一个用途是快速创建一个在其他任何地方都不需要的函数,然后将其传递给filter。

        5
  •  5
  •   Steve    17 年前

    我在回答我自己的问题,但是我在这里找到了匿名方法的一个很好的解释 Can your programming language do this?

        6
  •  1
  •   Svante    17 年前

    我猜(我不知道Delphi)这意味着现在可以将函数创建为一种数据对象。例如,这意味着您可以将函数作为参数传递给其他函数。示例:排序函数可能将比较函数作为参数,因此用途更广。

        7
  •  1
  •   F.D.Castel    17 年前

    匿名方法在函数式编程中很有用,但它们也可以帮助您在结构化编程中编写更紧凑的代码。线程,例如: http://blogs.codegear.com/abauer/2008/09/08/38868

    http://delphi.fosdal.com/2008/08/anonymous-methods-when-to-use-them.html

    推荐文章