Как вы вернетесь из функции в произвольной точке?

12

Как вы рано вернетесь из функции до ее завершения? Например:

(defun my-func () 
 "for example."
 (unless something (return nil))
 ; continue as usual...
 (+ 42 1))
ocodo
источник

Ответы:

19

У нас есть несколько вариантов.

бросать

Вы можете catch/, throwчтобы выйти из функции.

пример:

(defun my-func ()
  "thrown error"
  (catch 'my-catch
    (when t
      (throw 'my-catch "always going to throw"))
    (+ 42 1)))

блок

Вы также можете использовать blockи return-from(хотя вам потребуется cl-macs)

пример:

(require 'cl-macs)

(defun my-func ()
  "block / return-from"
  (block my-func
    (when t
      (return-from my-func))
    (+ 42 1)))

сл-DEFUN

У нас также cl-defunесть неявное имя blockс тем же именем, что и у функции, поэтому мы можем делать blockстиль с меньшими затратами.

пример:

(require 'cl-macs)

(cl-defun my-func ()
  "cl-defun implicit block"
  (when t
    (return-from my-func)) ; my-func is an implicit block.
  (+ 42 1)))

Defun *

cl-defunтакже доступен как псевдоним, defun*который определен cl.elтак:

(require 'cl)

(defun* my-func ()
  "defun* implicit block"
  (when t
    (return-from my-func)) ; my-func is an implicit block.
  (+ 42 1)))
ocodo
источник
4
Обратите внимание, что если у вас нет предпочтений в синтаксисе CL, catch/ throwявляется более идиоматичным в elisp, так как другие подходы в конечном итоге реализованы в терминах catch / throw. Elisp руководство говорит: «Большинство других версий Lisp, включая Common Lisp, есть несколько способов передачи управления nonsequentially: return, return-from, и go., Например , Emacs Lisp имеет только throw
Филс
5

В дополнение к тому, что описано в @EmacsFodder, просто выдайте ошибку.

Это не поможет, если код вызывается внутри (динамически, а не лексически) степени конструкций обработки ошибок, таких как ignore-errorsили condition-case, но в противном случае это хороший способ выхода из функции. Это на самом деле то, что делается большую часть времени.

(defun my-func () 
 "..."
 (unless something (error "Whoops!"))
 ; continue as usual...
 (+ 42 1))

Если вы хотите обработать ошибку самостоятельно, вы можете поместить вызывающий код (например, вызов чего-то, что вызывает неожиданно my-func) внутри a condition-case. Опять же, это то, что делается в большинстве случаев, по крайней мере, так же часто, как с помощью catch+ throw. Все зависит от того, какое поведение вы хотите.

Нарисовалась
источник
Спасибо за ответ, Дрю, я согласен, что это довольно распространенный метод. Однако простое раннее возвращение во многих других языках не влечет за собой сложность того, чтобы потом иметь дело с ошибкой. При исследовании вопроса / ответа задайте. Я специально искал альтернативы «ошибочному» стилю, который всегда кажется мне глупым. Я не указал это явно в тексте вопроса.
ocodo
1
Все зависит от того, что вы хотите сделать. Если вы хотите завершить работу немедленно, без дальнейшей обработки / обработки, то создание ошибки - хороший способ перейти на нелокальный выход в Emacs. Если вы хотите сделать что - то во время нелокального выхода, т.е., обрабатывать его в некотором роде, то catch, unwind-protect, condition-caseи т.п. полезны. Существует целый раздел руководства Elisp, посвященный нелокальным выходам . (И в них нет ничего особенно глупого, IMO.)
Дрю
«Чувствуется», конечно, совершенно субъективно. Спасибо за нелокальное руководство ref.
ocodo