Delphiでコールバック
※ 環境はDelphi 6
JavaScriptを触ってると、Delphiでもコールバックが使いたくなってきた。
調べてみると、わりと簡単にできるようだ。
コールバック(英: Callback)とは、プログラミングにおいて、他のコードの引数として渡されるサブルーチンである。
コールバック (情報工学) - Wikipedia
コールバック関数は、呼び出し先で何らかのイベントが発生した場合の処理を指定する目的で使われることが多い。コールバック関数を使うと、イベントの発生を検知するための処理と、そのイベントが起こった時に実行すべき個々の処理を分離して記述することができる。
コールバック関数とは - IT用語辞典 e-Words
手続き(関数)を渡す場合
まず、手続き型を宣言する。引数が違えば、違う手続き型として宣言しなければならない。
type TProc = procedure;
実装例
procedure MyProc; begin ShowMessage('This is MyProc'); end; procedure CallProc(Proc: TProc); begin Proc; end; procedure Main; procedure MyInnerProc; begin ShowMessage('This is MyInnerProc') end; begin CallProc(MyProc); // "This is MyProc" CallProc(@MyInnerProc); // "This is MyInnerProc" end;
関数内関数はポインタにして渡す。(そのまま渡すとコンパイル時エラーになる)
また、親関数の変数を扱おうとすると実行時エラーになる。
メソッドを渡す場合
同様に手続き型を宣言するが、末尾に「of Object」を付加する。
type TStrProc = procedure(s: String) of Object; TMyClass = class(TObject) public greet: String; constructor Create(s: String); procedure MyProc(msg: String); end; THisClass = class(TObject) public procedure HisProc(CallBack: TStrProc); end;
実装例
constructor TMyClass.Create(s: String); begin greet := s; end; procedure TMyClass.MyProc(msg: String); begin ShowMessage(greet + msg); // privateな変数にも触れる end; procedure THisClass.HisProc(CallBack: TStrProc); begin if Assigned(CallBack) then // <> nil ではなくAssignedを使う CallBack('This is Callback'); end; procedure Main; var Mine: TMyClass; His: THisClass; begin Mine := TMyClass.Create('Hi, '); His := THisClass.Create; His.HisProc(Mine.MyProc); // "Hi, This is Callback" His.Free; Mine.Free; end;
関数内関数は型違いとしてコンパイル時エラーになる。(ポインタにしてもコンパイル時エラー)
もちろん、コールバックがよばれる前にインスタンスが解放されていると実行時エラーになる。
また、関数が割り当てられているかの判定にはAssignedを使う(func <> nil としない)。