Примеры использования catch и throw
Один из способов использовать catch и throw — выйти из двойного вложенного цикла. (В большинстве языков это делается с помощью goto. Здесь мы вычисляем (foo i j) для i и j, изменяющихся от 0 до 9:
(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.
Вот два сложных примера, немного отличающиеся, демонстрирующие сразу две точки возврата. Во-первых, две точки возврата с одинаковым тегом, hack:
(defun catch2 (tag)
(catch tag
(throw 'hack 'yes)))
⇒ catch2
(catch 'hack (print (catch2 'hack)) 'no) -| yes ⇒ no
Поскольку обе точки возврата имеют теги, совпадающие с throw, выполняется внутренняя, установленная в catch2. Следовательно, catch2 возвращается нормально со значением yes, и это значение выводится. Наконец, второй блок кода во внешнем catch, который есть 'no, оценивается и возвращается из внешнего catch.
Теперь давайте изменим аргумент, переданный catch2:
(catch 'hack (print (catch2 'quux)) 'no) ⇒ yes
У нас все еще есть две точки возврата, но на этот раз только внешняя имеет тег hack, а внутренняя — quux. Следовательно, throw заставляет внешнюю catch вернуть значение yes. Функция print никогда не вызывается, и блок кода 'no никогда не оценивается.
Copyright © 1990-1996, 1998-2022 Free Software Foundation, Inc.
Licensed under the GNU GPL license.
https://www.gnu.org/software/emacs/manual/html_node/elisp/Examples-of-Catch.html