catch と throw の例 ¶catch と throw
の使い方の一つに、二重にネストされたループから抜けるというものがあります。(ほとんどの言語では、これは goto を用いて行われます。)ここでは、0から9まで変化する i
と j に対して (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))))))
If foo ever returns non-nil, we stop immediately and return a list of i and j. If foo always returns nil, the
catch returns normally, and the value is nil, since that is the result of the while.
ここでは、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に与えられた引数を変更しましょう:
(catch 'hack (print (catch2 'quux)) 'no) ⇒ yes
戻り値の箇所はまだ2つありますが、今回は外側の箇所にのみタグ hack
が付いており、内側の箇所には代わりにタグ quux が付いています。したがって、throw によって外側の catch が値 yes を返します。関数 print
が呼び出されることはなく、ボディフォーム 'no が評価されることもありません。