Spec-Zone.ru › Elisp

Явные нелокальные выходы: catch и throw

Большинство управляющих конструкций влияют только на поток управления внутри самой конструкции. Функция throw является исключением из этого правила нормального выполнения программы: она выполняет нелокальный выход по запросу. (Есть и другие исключения, но они предназначены только для обработки ошибок.) throw используется внутри catch, и переходит обратно к этому catch. Например:

(defun foo-outer ()
  (catch 'foo
    (foo-inner)))

(defun foo-inner ()
  …
  (if x
      (throw 'foo t))
  …)

Форма throw, если выполняется, передает управление прямо обратно соответствующему catch, который возвращается немедленно. Код, следующий за throw, не выполняется. Второй аргумент throw используется в качестве возвращаемого значения catch.

Функция throw находит соответствующий catch на основе первого аргумента: она ищет catch, чьим первым аргументом является eq к указанному в throw. Если существует более одного подходящего catch, то используется самый внутренний. Таким образом, в приведенном выше примере throw указывает на foo, а catch в foo-outer указывает на тот же символ, так что catch является подходящим (при условии, что нет другого соответствующего catch между ними).

Выполнение throw выходит из всех конструкций Lisp до соответствующего catch, включая вызовы функций. При выходе из конструкций связывания, таких как let или вызовов функций, связывания отменяются, точно так же, как при нормальном выходе из этих конструкций (см. Локальные переменные). Аналогично, throw восстанавливает буфер и позицию, сохраненные save-excursion (см. Экскурсии), и состояние сужения, сохраненное save-restriction. Также выполняет любые очищающие действия, установленные с помощью специальной формы unwind-protect при выходе из этой формы (см. Очистки).

throw не обязательно должен появляться лексически внутри catch, к которому он переходит. Он может быть вызван и из другой функции, вызываемой внутри catch. До тех пор, пока throw происходит хронологически после входа в catch и хронологически перед выходом из него, он имеет доступ к этому catch. Вот почему throw можно использовать в командах, таких как exit-recursive-edit, которые возвращаются в цикл команд редактора (см. Рекурсивный редактирование).

Примечание Common Lisp: Большинство других версий Lisp, включая Common Lisp, имеют несколько способов передачи управления не последовательно: return, return-from, и go, например. Emacs Lisp имеет только throw. Библиотека cl-lib предоставляет версии некоторых из них. См. Блоки и выходы в Расширения Common Lisp.

Специальная форма: catch метка тело…

catch устанавливает точку возврата для функции throw. Точка возврата отличается от других таких точек возврата меткой, которая может быть любым объектом Lisp, кроме nil. Аргумент метка оценивается обычно перед установлением точки возврата.

После установления точки возврата catch вычисляет формы тела в текстовом порядке. Если формы выполняются нормально (без ошибок или нелокального выхода), значение последней формы тела возвращается из catch.

Если во время выполнения тела выполняется throw, указывая то же значение метка, то форма catch завершается немедленно; значение, которое она возвращает, — это то, что было указано в качестве второго аргумента throw.

Функция: throw метка значение

Цель throw — вернуть значение из точки возврата, ранее установленной с помощью catch. Аргумент метка используется для выбора среди различных существующих точек возврата; он должен быть eq к значению, указанному в catch. Если несколько точек возврата соответствуют метка, используется самая внутренняя.

Аргумент значение используется в качестве значения для возврата из этой catch.

Если точка возврата с меткой метка не установлена, то сигнализируется ошибка no-catch с данными (tag value).

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/Catch-and-Throw.html

Spec-Zone.ru

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