7.7 Блоки и выходы

Конструкции block и return-from предоставляют функциональность для структурированного лексического нелокального выхода. В любом месте лексически внутри конструкции block, для мгновенного возврата управления из block может быть использована return-from с тем же именем. В большинстве случаев этот механизм более эффективный, чем функциональность динамического нелокального выхода, предоставляемая формами catch и throw, описанными в разделе 7.11.

[Специальный оператор] block name {form}*

Конструкция block слева направо выполняет каждую форму form, возвращая то, что возвращает последняя форма. Если, однако, в процессе выполнения форм, будет выполнена return или return-from с именем name, тогда будет возвращён результат заданный одной из этих форм, и поток выполнения немедленно выйдет из формы block. Таким образом block отличается от progn тем, что последняя никак не реагирует на return.

Имя блока не выполняется. Оно должно быть символом. Область видимости имени блока лексическая. Из блока можно осуществить выход с помощью return или return-from, только если они содержаться в тексте в блоке. Продолжительность видимости имени динамическая. Таким образом из блока во время выполнения можно выйти только один раз, обычно или явно с помощью return.

Форма defun неявно помещает тело функции в одноимённый блок. Таким образом можно использовать return-from для преждевременного выхода из функции в определении defun.

Лексическая область видимости имени блока полноценна и имеет последствия, которые могут быть сюрпризом для пользователей и разработчиков других Lisp систем. Например, return-from в следующем примере в Common Lisp работает так как и ожидается:

(block loser
   (catch ’stuff
      (mapcar #’(lambda (x) (if (numberp x)
                                (hairyfun x)
                                (return-from loser nil)))
              items)))

В зависимости от ситуации, return в Common Lisp’е может быть не проста. return может перескочить ловушки, если это необходимо, для рассматриваемого блока. Также возможно для «замыкания», созданного с помощью function для лямбда-выражения, ссылаться на имя блока на протяжении лексической доступности этого блока.


[Специальный оператор] return-from name [result]

return-from используется для возврата из block или из таких конструкций, как do и prog, которые неявно устанавливают block. Имя name не выполняется и должно быть символом. Конструкция block с этим именем должна лексически охватывать форму return-from. Каков бы ни был результат вычисления формы result, управление немедленно возвращается из блока. (Если форма result опущена, тогда используется значение nil. В целях стиля, эта форма обязана использоваться для указания того, что возвращаемое значение не имеет ценности.)

Форма return-from сама по себе ничего и никогда не возвращает. Она указывает на то, что результат выполнения будет возвращён из конструкции block. Если вычисление формы result приводит к нескольким значениям, эти несколько значений и будут возвращены и конструкции.


[Макрос] return [result]

(return form) идентично по смыслу (return-from nil form). Она возвращает управление из блока с именем nil. Такие блоки с именем nil устанавливаются автоматически в конструкциях циклов, таких как do, таким образом return будет производить корректный выход из таких конструкций.