Next: Errors, Previous: Catch and Throw, Up: Nonlocal Exits
catch
とthrow
の例catch
とthrow
の使い方の1つは、
2重のループからの脱出です。
(ほとんどの言語では、これを『go to』で行うであろう。)
ここでは、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
以外を返すと、
ただちに止まってiとjのリストを返します。
foo
がつねにnil
を返すと、
catch
は通常どおりに戻って、その値はnil
です。
というのは、while
の結果はnil
だからです。
2つの巧妙な例をあげましょう。
多少異なる2つの戻り位置が同時に存在します。
まず、同じタグhack
で2つの戻り位置があります。
(defun catch2 (tag) (catch tag (throw 'hack 'yes))) catch2 (catch 'hack (print (catch2 'hack)) 'no) -| yes no
どちらの戻り位置もthrow
に一致するタグなので、
内側のもの、つまり、catch2
で確立したものに戻ります。
したがって、catch2
は値yes
で通常どおり戻り、
この値が表示されます。
最後に、外側のcatch
の2番目の本体フォーム、
つまり、'no
が評価され、外側のcatch
から戻ります。
今度は、catch2
に指定する引数を変更してみます。
(defun catch2 (tag) (catch tag (throw 'hack 'yes))) catch2 (catch 'hack (print (catch2 'quux)) 'no) yes
ここでも2つの戻り位置がありますが、
今度は外側のものだけがタグhack
です。
内側のものはタグquux
です。
したがって、throw
により、外側のcatch
が値yes
を返します。
関数print
はけっして呼ばれず、
本体フォーム'no
もけっして評価されません。