Next: Examples of Catch, Up: Nonlocal Exits [Contents][Index]
catch
and throw
ほとんどの制御構造は、そのコンストラクト自身内部の制御フローだけに影響します。関数throw
は、通常のプログラム実行でのこのルールの例外です。これは、リクエストにより非ローカル脱出を行ないます(他にも例外はありますが、それらはエラー処理だけのものです)。throw
はcatch
の内部で試用され、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
で指定されたものとeq
なcatch
を検索します。複数の該当するcatch
がある場合、最内のものが優先されます。したがって、上記の例ではthrow
がfoo
を指定し、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する前である限り、そのthrow
はcatch
にアクセスできます。エディターのコマンドループから戻るexit-recursive-edit
のようなコマンドで、throw
が使用されるのは、これが理由です。
Common Lispに関する注意: Common Lispを含む、他のほとんどのバージョンのLispは、非シーケンシャルに制御を移す、いくつかの方法 — たとえば
return
、return-from
、go
— をもちます。Emacs Lispの場合は、throw
だけです。cl-libライブラリーは、これらのうちいくつかを提供します。Blocks and Exits in Common Lisp Extensionsを参照してください。
catch
は、throw
関数にたいするreturn位置を確立します。return位置はtagにより、そのような他のreturn位置と区別されます。tagは、nil
以外の任意のLispオブジェクトです。引数tagはreturn位置が確立される前に、通常どおり評価されます。
return位置が効果をもつことにより、catch
はbodyのフォームをテキスト順に評価します。フォームが(エラーは非ローカル脱出なしで)通常に実行された場合、bodyの最後のフォームの値が、catch
からreturnされます。
bodyの実効の間にthrow
が実行された場合、tagと同じ値を指定すると、catch
フォームは即座にexitします。returnされる値は、それが何であれ、throw
の2番目の引数に指定された値です。
throw
の目的は、以前にcatch
により確立されたreturn位置に戻ることです。引数tagは、既存のさまざまなreturn位置からrturn位置を選択するために使用されます。複数のreturn位置がtagにマッチする場合、最内のものが使用されます。
引数valueは、catch
からreturnされる値として使用されます。
タグtagのreturn位置が存在しない場合、データ(tag
value)
とともに、no-catch
エラーがシグナルされます。