Next: , Up: Nonlocal Exits   [Contents][Index]


10.5.1 Explicit Nonlocal Exits: catch and throw

ほとんどの制御構造は、そのコンストラクト自身内部の制御フローだけに影響します。関数throwは、通常のプログラム実行でのこのルールの例外です。これは、リクエストにより非ローカル脱出を行ないます(他にも例外はありますが、それらはエラー処理だけのものです)。throwcatchの内部で試用され、catchに制御を戻します。たとえば:

(defun foo-outer ()
  (catch 'foo
    (foo-inner)))

(defun foo-inner ()
  …
  (if x
      (throw 'foo t))
  …)

throwフォームが実行された場合は、対応するcatchに制御を移し、catchは即座にreturnします。throwの後のコードは実行されません。throwの2番目の引数は、catchのreturn値として使用されます。

関数throwは、1番目の引数にもとづいて、それにマッチするcatchを探します。throwは、1番目の引数が、throwで指定されたものとeqcatchを検索します。複数の該当するcatchがある場合、最内のものが優先されます。したがって、上記の例ではthrowfooを指定し、foo-outer内のcatchが同じシンボルを指定しているので、(この間に他のマッチするcatchは存在しないと仮定すると)catchが該当します。

throwの実行により、マッチするcatchまでのすべてのリスプ構成(関数呼び出しを含む)を脱出します。この方法によりletや関数呼び出しのようなバインディング構成を脱出する場合、これらの構成を正常にexitしたときのように、そのバインディングは解かれます(Local Variablesを参照してください)。同様にthrowは、save-excursion(Excursionsを参照してください)により保存されたバッファーと位置を復元します。throwが、スペシャルフォームunwind-protectを脱出した場合、unwind-protectにより設定されたいくつかのクリーンアップも実行します。

ジャンプ先となるcatch内にレキシカル(局所的)である必要はありません。throwは、catch内で呼び出された別の関数から、同じようにに呼び出すことができます。throwが行なわれたのが、順序的に、catchに入った後でexitする前である限り、そのthrowcatchにアクセスできます。エディターのコマンドループから戻るexit-recursive-editのようなコマンドで、throwが使用されるのは、これが理由です。

Common Lispに関する注意: Common Lispを含む、他のほとんどのバージョンのLispは、非シーケンシャルに制御を移す、いくつかの方法 — たとえばreturnreturn-fromgo — をもちます。Emacs Lispの場合は、throwだけです。cl-libライブラリーは、これらのうちいくつかを提供します。Blocks and Exits in Common Lisp Extensionsを参照してください。

Special Form: catch tag body…

catchは、throw関数にたいするreturn位置を確立します。return位置はtagにより、そのような他のreturn位置と区別されます。tagは、nil以外の任意のLispオブジェクトです。引数tagはreturn位置が確立される前に、通常どおり評価されます。

return位置が効果をもつことにより、catchbodyのフォームをテキスト順に評価します。フォームが(エラーは非ローカル脱出なしで)通常に実行された場合、bodyの最後のフォームの値が、catchからreturnされます。

bodyの実効の間にthrowが実行された場合、tagと同じ値を指定すると、catchフォームは即座にexitします。returnされる値は、それが何であれ、throwの2番目の引数に指定された値です。

Function: throw tag value

throwの目的は、以前にcatchにより確立されたreturn位置に戻ることです。引数tagは、既存のさまざまなreturn位置からrturn位置を選択するために使用されます。複数のreturn位置がtagにマッチする場合、最内のものが使用されます。

引数valueは、catchからreturnされる値として使用されます。

タグtagのreturn位置が存在しない場合、データ(tag value)とともに、no-catchエラーがシグナルされます。