DelFusa Blog 総本山

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

NEW | PAGE-SELECT | NEXT

≫ EDIT

スポンサーサイト

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

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

≫ EDIT

無名メソッド&ジェネリックで、local.block<> Function


   ∧⊂ヽ  / ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄
  ミ,,゚Д゚ミ< どやー
   ミ ⊃ ミ  \_________
   ミ⊂ノ~
   ∪


さて、前回のどや顔から引き続きます。

前回とは、これ。

DelFusaBlog なんだ、無名メソッドを使えばローカルブロック変数は簡単なんじゃないか。
http://delfusa.blog65.fc2.com/blog-entry-272.html


そう。
VB.NETとかC#とかをみて、
Delphi使いの誰もがちょっと憧れ、そして誰もがかかってしまう

『その場でローカル変数宣言したいのに
メソッド(関数/手続き)先頭でしか変数宣言できないのは不便だわ症候群』

その解消方法の秘伝を前回はお伝えしました。

今回は、そのFunction版。

別にFunction版なんかいらない!といえば確かにいらないんですが、
なんで作りたくなったかというと

ParamStrのParamStr(1~Count)まで全部を合算して取得したかったから。
独立した関数として作成するのでもよかったのですが、なんか思い立って、無名メソッド戻り値で表現したくなりました。

その場でコピペして貼り付けられるコードにもなりますからね。
ということで、実験ソースコード、どぞー。


function block_string(f: TFunc<String>): string;
begin
 Result := f;
end;

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

 ShowMessage(
  block_string(function: string
  var
   a, b: string;
  begin
   a := 'A';
   b := 'B';
   Result := s + a+ b;
  end ) ); //TESTAB と表示される
end;

こうやってStringを返す関数をその場で作って実行して引数を取得することができます。

残念な事に、このようには書けない様子。
function block<TResult>(f: TFunc<TResult>): TResult;
begin
 Result := f;
end;
次のエラーが出ます。
[DCC エラー] Unit1.pas(124): E2530 型パラメータはグローバル プロシージャや関数で許可されません。

ということは、グローバルでないProcedureなら書けるということです。

なので、次のコードはOK。

type
 local = class
 private
 public
  class function result<TResult>(f: TFunc<TResult>): TResult;
 end;
class function local.result<TResult>(f: TFunc<TResult>): TResult;
begin
 Result := f;
end;

procedure TForm1.Button5Click(Sender: TObject);
var
 s: String;
begin
 s := 'TEST';
 s := s +
  local.result<string>(function: string
  var
   a, b: string;
  begin
   a := 'A';
   b := 'B';
   Result := a + b + s;
  end );
 ShowMessage(s); //TESTABTEST と表示される

 s := 'TEST';
 s := s + IntToStr(
  local.result<Integer>(function: Integer
  var
   a, b: Integer;
  begin
   a := 1;
   b := 2;
   Result := a + b;
  end ) );
 ShowMessage(s); //TEST3 と表示される
end;

ちゃんとfunction を引数として渡してそれが即実行されてすぐに戻り値をとってくれます。
まあ、上位スコープのsに代入しちゃえばいいんですが、
それはそこで、ほら、いずれ汎用化させるときにResultに代入しておきたいのが
プログラマ根性みたいなものじゃないっすか!

さてさて、上記では、、
local.result<Integer>(無名関数begin end) となっているので、endの後に括弧がくるので少し変な感じ。

まあ、この変な感じこそが無名関数を使っているということが分かってよさそうな気もしますが・・・

それは置いておいて、プロパティとして無名関数ぶっ込みの
前回の、local.block := procedure構文と同じことをやってみます。


type
 local<TResult> = class
 private
  class var FValue: TResult;
// class var Ffunc: TFunc<TResult>;
  class procedure SetBlock(const Value: TFunc<TResult>); static;
 public
  class function result: TResult;
  class property block: TFunc<TResult> write SetBlock;
 end;

class procedure local<TResult>.SetBlock(const Value: TFunc<TResult>);
begin
// Ffunc := Value;
 FValue := Value;
end;
class function local<TResult>.result: TResult;
begin
// Result := Ffunc;
 Result := FValue;
end;

procedure TForm1.Button6Click(Sender: TObject);
var
 s: String;
begin
 s := 'TEST';
 local<string>.block := function: string
 var
  a, b: string;
 begin
  a := 'A';
  b := 'B';
  Result := a + b + s;
 end;
 s := s + local<string>.result;
 ShowMessage(s); //TESTABTEST と表示される

 s := 'TEST';
 local<Integer>.block := function: Integer
 var
  a, b: Integer;
 begin
  a := 1;
  b := 2;
  Result := a + b;
 end;
 s := s + IntToStr(local<Integer>.result);
 ShowMessage(s); //TEST3 と表示される
end;

local<TResult> = class で
今の実装は代入時点で動作して戻り値を保持。
コメントアウトしているコードでは Functionを保持しておいてresultを呼び出したときに実行してます。

ということで、
  local<Integer>.block := function: Integer
  var
   ・・・
  begin

  end;

  local<Integer>.result
という、すっきりしてそうで、すっきりしてない、少しすっきりしている、変なコードが書けるようになりました。

ご参考に・・・・ならないと思いますが、ご参考に。




※それにしても、わんくま、っていう同盟の人たちが.NET界隈にいるようなのですが
 前回記事のリンク先のわんくまのサーバーが、すさまじい全落ちしている様子。
 アナウンス場所も落ちているという、すごい具合です。

 フサギコは犬だという噂もありますが、猫で孤独です。同盟とかないです。

 誰か、Delphi勉強会とかしないかしらね。
 都内とか。
スポンサーサイト

| 未分類 | 01:35 | comments:0 | trackbacks(-) | TOP↑

COMMENT















非公開コメント

PREV | PAGE-SELECT | NEXT

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