Come si ritorna da una funzione in un punto arbitrario?


12

Come si fa a tornare presto da una funzione prima che sia terminata? Per esempio:

(defun my-func () 
 "for example."
 (unless something (return nil))
 ; continue as usual...
 (+ 42 1))

Risposte:


19

Abbiamo un numero di opzioni disponibili.

Gettare

È possibile catch/ throwper uscire dalla funzione.

esempio:

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

Bloccare

Puoi anche usare blocke return-from(anche se dovrai richiederlo cl-macs)

esempio:

(require 'cl-macs)

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

cl-defun

Abbiamo anche cl-defunun implicito blockcon lo stesso nome della funzione, quindi possiamo fare lo blockstile con meno.

esempio:

(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è anche disponibile come alias defun*che è definito in questo cl.elmodo:

(require 'cl)

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

4
Si noti che se non si ha una preferenza per la sintassi CL, catch/ throwè più idiomatico in elisp, poiché altri approcci vengono infine implementati in termini di cattura / lancio. Il manuale elisp dice: "La maggior parte delle altre versioni di Lisp, tra cui Common Lisp, hanno diversi modi di trasferire il controllo non sequenziale: return, return-from, e go., Per esempio Emacs Lisp ha solo throw."
phils,

5

Oltre a ciò che ha riguardato @EmacsFodder, basta generare un errore.

Ciò non sarà d'aiuto se il codice viene chiamato all'interno (in modo dinamico, non lessicale) dell'estensione dei costrutti di gestione degli errori come ignore-errorso condition-case, ma per il resto è un ottimo modo per uscire da una funzione. In realtà è ciò che viene fatto la maggior parte delle volte.

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

Se si desidera gestire da soli l'errore, è possibile inserire il codice chiamante (ad es. La chiamata a qualcosa che chiama in via definitiva my-func) all'interno di a condition-case. Ancora una volta, questo è ciò che viene fatto la maggior parte delle volte, almeno tutte le volte che si utilizza catch+ throw. Tutto dipende dal comportamento che desideri.


Grazie per la risposta Drew, sono d'accordo che questo è un metodo abbastanza comune. Tuttavia, il semplice ritorno in molte altre lingue non comporta la complessità di dover affrontare un errore. Durante la ricerca del set di domande / risposte. In particolare, ero alla ricerca di alternative allo stile di "errore", che mi fa sempre ridere. Non l'ho specificato esplicitamente nel testo della domanda, intendiamoci.
ocodo

1
Tutto dipende da cosa vuoi fare. Se vuoi terminare immediatamente, senza ulteriori elaborazioni / manipolazioni, generare un errore è un buon modo per uscire non localmente, in Emacs. Se si vuole fare qualcosa nel corso di un'uscita non locale, vale a dire, di gestire in qualche modo, quindi catch, unwind-protect, condition-casee simili sono utili. C'è un'intera sezione del manuale Elisp dedicata alle uscite non locali . (E non c'è niente di particolarmente kludgy su uno di essi, IMO.)
Drew

"Feels" è del tutto soggettivo, ovviamente. Grazie per il riferimento manuale non locale.
ocodo,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.