Next: Errors, Previous: Catch and Throw, Up: Nonlocal Exits [Contents][Index]
catch
and throw
2重にネストされたループから脱出する1つの方法は、catch
とthrow
を使うことです(ほとんどの言語では、これは“goto”により行なわれるでしょう)。ここでは、iとjを、0から9に変化させて(foo
i j)
を計算します:
(defun search-foo () (catch 'loop (let ((i 0)) (while (< i 10) (let ((j 0)) (while (< j 10) (if (foo i j) (throw 'loop (list i j))) (setq j (1+ j)))) (setq i (1+ i))))))
foo
が非nil
をreturnした場合、即座に処理を止めて、iとjのリストをreturnしています。foo
が常にnil
をreturnする場合、catch
は通常どおりreturnし、その値はwhile
の結果であるnil
となります。
以下では、2つのreturn位置を1度に表す、微妙に異なるトリッキーな例を2つ示します。最初に、同じタグhack
にたいする2つのreturn位置があります:
(defun catch2 (tag) (catch tag (throw 'hack 'yes))) ⇒ catch2
(catch 'hack (print (catch2 'hack)) 'no) -| yes ⇒ no
どちらのreturn位置もthrow
にマッチするタグをもつので、内側のもの、つまりcatch2
で確立されたものにgotoします。したがってcatch2
は通常どおり値yes
をreturnするので、その値がプリントされます。最後に外側のcatch
の2番目のbody、つまり'no
が評価されて、外側のcatch
からそれがreturnされます。
ここで、catch2
に与える引数を変更してみます:
(catch 'hack (print (catch2 'quux)) 'no) ⇒ yes
この場合も2つのreturn位置がありますが、今回は外側だけがタグhack
をもち、内側のものは、かわりにタグquux
をもちます。したがって、throw
により、外側のcatch
が値yes
をreturnします。関数print
が呼び出されることはなく、bodyのフォーム'no
も決して評価されません。