次: Errors, 前: Catch and Throw, 上: 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
もけっして評価されません。