C言語で関数ポインタを必要としていたような処理には、D言語の場合も同様の関数ポインタが使えるほか、delegate も使用可能です。
- delegate, 関数ポインタ, 動的クロージャ
関数ポインタとdelegateの明確な違いは、this を持てるかどうかだと考えれば良さそうです。
簡単なサンプルを。
import tango.io.Stdout;
class Controller {
private char[] delegate()[char[]] actionList;
void registAction(char[] action, char[] delegate() fn) {
actionList[action] = fn;
}
char[] execAction(char[] action) {
return actionList[action]();
}
}
class ListController : Controller {
this() {
registAction("do", &doAction);
registAction("queue", &queueAction);
}
char[] doAction() {
return "do";
}
char[] queueAction() {
return "this is queue action.";
}
}
void main(char[][] args) {
ListController c = new ListController;
Stdout(c.execAction(args[1])).newline;
}
class Controller で、delegate の配列を宣言しています。
ここに継承先のクラスのメンバ関数を連想配列に保管しておき、コマンドラインから指定された文字列によって、呼び出すメンバを切り替えています。
$ ./main do do $ ./main queue this is queue action. $ ./main error tango.core.Exception.ArrayBoundsException@main(12): Array index out of bounds
ここでは、クラスのコード内、this() にて、いちいちメンバ関数を登録するような処理を行なっていますが、これは非常に間違いやすく忘れやすい処理かと思います。
この部分は以前書いたCTFEと組み合わせることで、このregistActionを自動生成させたうえでコンパイルすることが可能ですから、実質的にクラスの定義を行なうだけで動的に呼び出すメンバを切り替えることは難しい話ではありません。
そんなわけで、なかなかD言語にリフレクションの仕組みが組み込まれないと言われ続けていますが、特にクラスの中を解析する必要でもない限りリフレクションいらないやんとか思っているのは私だけでしょうかね?
