DelFusa Blog 総本山

プログラミングの話題とかです。

NEW | PAGE-SELECT | NEXT

≫ EDIT

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

| スポンサー広告 | --:-- | comments(-) | trackbacks(-) | TOP↑

≫ EDIT

なんだ、無名メソッドを使えばローカルブロック変数は簡単なんじゃないか。


           _____________
   ∧,,∧∩  /
  ミ,,゚Д゚彡 < どや?
  (ミ   ミ   \
 ~ミ ,,, ミ      ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄
   し' `J


DelphiXEを結構つかってきていまして、Unicodeにはなれてきたところですが、無名メソッドなどには手を出していませんでした。

XEだけじゃなく、旧バージョンも使っていまして、このあたりを見て簡単にわかるように
DelFusaBlog D3でも動くStringReplaceと、パラメータクエリーを変換する関数
http://delfusa.blog65.fc2.com/blog-entry-270.html
メソッドポインタを使って存分にコードを書くことができるので
無名メソッドには特にメリットを感じなかったのですが、

いまさらながらのDELPHI2009ハンドブック、P207辺りを見ますと、無名メソッドの強力さがわかってきました!



無名メソッドを使うと、ブロック変数が簡単に実現できてしまいます。
Javaではクロージャーという用語で使われているものと同じ機能をもっているんですね。

言語的にはそんなたいしたことはないのかもしれないが、開発者にはブロック変数を気軽に使えるというのは、メリットが大きいものです。

いつのまにか、その場で変数宣言的にコードを書くことが可能になっていたとは、驚いたぜ。教えてくれよ、エンバカさん・・・
なぜ誰もこんな使い方をしていないんだ?便利じゃないか!


Delphiでも直接的に空ブロック的な変数スコープは用意されてません。
VB.NETでも言語的には空ブロックがないですが、このようにすると実現できるそうです。

・VB.NET で C# の { } 空ブロックと同じことをするには?
http://blogs.wankuma.com/jeanne/archive/2006/11/07/43926.aspx



で、これと同じことをDelphiでは無名メソッドをチョチョイと応用することで実現できるわけです。

ごくごく簡単なソースがこちら。

procedure block(p: TProc);
begin
 p;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
 s: String;
begin
 s := 'TEST';

 block(procedure
 var
  a: Integer;
  b: Integer;
 begin
  a := 1;
  b := 2;
  s := s + IntToStr(a+b);
 end );

 ShowMessage(s); //TEST3 と表示される
end;

block関数に無名メソッドを渡して即実行させて、それが上位スコープ(ここでは変数s)の値を書き換えることができます。

このように上位スコープにアクセスできるのはC#の無名(匿名?)メソッドでも同じなのですね。

第5回 匿名メソッドとデリゲート - @IT
http://www.atmarkit.co.jp/fdotnet/csharp20/csharp20_05/csharp20_05_02.html




上記のblock変数による、Delphiの空ブロック記述方法は
 block(procedure
 var 変数宣言;
 begin
  処理
 end );
という、なんか、endの後に括弧閉じるがある、慣れにくい記述になるのでもう少し違った書き方も示しておきましょう。

type
 local = class
 private
  class procedure SetBlock(const Value: TProc); static;
 public
  class property block: TProc write SetBlock;
 end;

class procedure local.SetBlock(const Value: TProc);
begin
 Value;
end;

procedure TForm1.Button2Click(Sender: TObject);
var
 s: string;
begin
 s := 'TEST';

 local.block := procedure
 var
  a: Integer;
  b: Integer;
  I: Integer;
 begin
  a := 1;
  b := 2;
  s := s + '-' +IntToStr(a+b);

  a := 0;
  for I := 0 to 10 do
  begin
   a := a + I;
  end; //0+1+2+…10=55

  s := s + '-' +IntToStr(a);
 end;

 ShowMessage(s); //TEST-3-55 と表示される
end;

これで、ブロックの宣言を
 local.block := procedure
 var 変数宣言;
 begin
  処理
 end;
と、記述することができます。

こんな記載もOKのようです。
procedure TForm1.Button3Click(Sender: TObject);
var
 I: Integer;
 Value: Integer;
begin
 Value := 0;
 for I := 0 to 9 do
 begin

  local.block := procedure
  var
   I: Integer;
  begin

   for I := 0 to 9 do
    local.block := procedure
    var
     a: Integer;
     I: Integer;
    begin
     a := 0;
     for I := 0 to 10 do
     begin
      a := a + I;
     end;
     Value := Value + a;
    end;

  end;

 end;

 ShowMessage(IntToStr(Value));
 //55*10*10で、5500と表示される
end;

そういえば、なんかForループのローカル変数をその場で宣言OKにならんか?的な試験をしていたときに、無名メソッドとヒントを教えようとしてくれたコメントがあった気がしましたが、こういうことだったのですね。

『上位スコープを見ることができる』なんていうことができると思っていなかったので、すっかり見過ごしてしまっていました。

いや、念願の「変数その場で宣言して使える」仕組みが、こんな風に存在しているとは驚きました。

また、Delphiコーディングスタイルを変えて楽しくやっていけそうです。

そういえば、DELPHI 2009 HANDBOOKには自動破棄のSmartPointer実装も
すごい詳細に書いてありますね。

これも便利かも。
スポンサーサイト

| 未分類 | 00:14 | comments:0 | trackbacks(-) | TOP↑

COMMENT















非公開コメント

PREV | PAGE-SELECT | NEXT

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。