Spec-Zone.ru › Elisp

Примеры использования 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

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API