デリゲート
デリゲートは、AliceScriptにおける”匿名関数”のメカニズムです。デリゲートは匿名関数として、その場ですぐに実行したり、変数に代入したり、関数に引数として渡すことができます。
例えば、蔵書検索アプリケーションを作成することを考えてみましょう。この検索にはAND検索、OR検索、完全一致検索が用意されています。 いずれの場合も、Seartch()関数が行うことは基本的に同じです。つまり、なんらかの条件に基づいて一連の蔵書から項目を検索します。しかし、条件に基づいて検索するコードはそれぞれの条件によって異なります。
ソフトウェアには、この種の手法が半世紀にわたって使用されてきました。AliceScriptのデリゲートは、さらに思い通りのプログラミングを実現します。
この記事ではdelegate
キーワードとそれによって生成されるコード、delegate
型に実装される機能を説明します。
名前空間 | Alice |
アセンブリ | ローカル |
サポート | AliceScript1 |
属性 | 言語構造 |
基本
デリゲート型は、delegate
キーワードまたはその省略表現_
と、そのデリゲートの実行に必要な引数を指定して宣言されます。
引数はかっこで囲み、各引数をコンマで区切ります。括弧内を空にすると、デリゲートは引数が不要なことを意味します。
デリゲートを同期的に呼び出すには関数のように丸括弧を使用して呼び出すか、Invoke
メソッド使用し、非同期的に呼び出すにはBeginInvoke
メソッドを使用します。
また基本的には、引数の指定方法や戻り値に関する詳細は関数と同じです。詳しく知るには関数の記事も参照してください。
次の例にはデリゲートを生成し、それをSayHello
として定義します。SayHello
が呼び出されたとき、標準出力にHello,World!を書き込みます。
var SayHello = _() { print("Hello,World!"); } SayHello();//出力例:Hello,World!
関数からの暗黙的な変換
ほとんどのネイティブ関数とユーザー定義関数は、デリゲート型の変数へと暗黙的に変換できます。ユーザー定義関数を丸括弧なしで呼び出すと、それはその関数をデリゲート型に変換されたオペランドと認識されます。次に例を示します。
function SayHello() { print(“Hello,World”); } var hello=SayHello;//helloは、DELEGATE型を表します hello();//出力:Hello,World
ただし、以下の属性を持っている関数を暗黙的に変換することはできません。
- 言語構造
- 関数の区切り文字の空白をサポート
- 単一の引数のみ関数の区切り文字の空白をサポート
また、FunctionBase型を継承しない関数も、この機能をサポートしません。
関数の属性について詳しく知るには、関数の記事を参照してください。
デリゲートの組み合わせ
デリゲート型は、複数のデリゲートを一つに結合することができます。組み合わされたデリゲートの各ステートメントは、順番に実行され、foreach
文を使用して一つずつに分解することも可能です。上記の例ですでにSayHello
を定義しましたから、もう一つ、SayBonjur
デリゲートを定義し、それらを結合して実行する例を示します。
var SayBonjur = _() { print(“Bonjur”); } var Say = SayHello+SayBonjur; Say(); //出力例:Hello,World! // :Bonjur
イベント駆動型プログラム
イベント駆動型プログラムは例えば「キーボードが押下された」とか、「マウスが移動した」などの受動的なイベントの発生によってコードが実行されるプログラムです。AliceScriptでは、デリゲート型とその組み合わせによって実現できます。ここでは簡単なサンプルとして、1秒おきにHello,Worldを表示し続け、それをeキーが押下されたときに停止するプログラムを作成します。このコードでは非同期的に1秒前にHello,Worldを表示し続け、同時に同期的にキーの押下を待機し続け、なんらかのキーが押下されたときにOnkeyDown
にキーの情報を渡して呼び出します。
var OnKeyDown; (_(){ //非同期に実行されるコード while(true) { OnKeyDown(Console_ReadKey()); } }).BeginInvoke(); //OnKeyDownに次のコードをイベントハンドラとして登録します OnKeyDown+=_(key) { if(key==“e”) { exit; } } while(true) { print(“Hello,World”); delay(1000); }
実際に実行すると次のように動作します。
Hello,World Hello,World Hello,World Hello,World eキーを押下すると終了します
Invoke
variable delegate.Invoke(params args);
現在のデリゲートに指定された引数を渡して実行し、その戻り値を返します。
BeginInvoke
void delegate.BeginInvoke(params args);
現在のデリゲートをすべて非同期で実行します。
Length/Count
number delegate.Length; number delegate.Count;
現在のデリゲートに含まれる要素の数を返します。