Qual è la differenza tra la generazione di eccezioni e la generazione di eccezioni in Ruby?
Domanda
Ruby ha due diversi meccanismi di eccezione:Lancia/Prendi e Rilancia/Salva.
Perché ne abbiamo due?
Quando dovresti usare l'uno e non l'altro?
Soluzione
Penso http://hasno.info/ruby-gotchas-and-caveats ha una spiegazione decente della differenza:
prendere/lanciare non sono la stessa cosa di rilanciare/salvare.catch/throw ti consente di uscire rapidamente dai blocchi fino al punto in cui è definito un catch per un simbolo specifico, raise Rescue è la vera gestione delle eccezioni che coinvolge l'oggetto Exception.
Altri suggerimenti
raise
,fail
,rescue
, Eensure
maniglia errori, conosciuto anche come eccezionithrow
Ecatch
Sono flusso di controllo
A differenza di altre lingue, il lancio e la cattura di Ruby non sono usati per eccezioni.Invece, forniscono un modo per interrompere l'esecuzione in anticipo quando non sono necessari ulteriori lavori.(Grimm, 2011)
Terminare un singolo livello di flusso di controllo, come a while
loop, può essere fatto con un semplice return
.È possibile terminare molti livelli di flusso di controllo, come un ciclo annidato throw
.
Sebbene il meccanismo di eccezione di raise e salvataggio sia ottimo per abbandonare l'esecuzione quando le cose vanno male, a volte è bello poter saltare fuori da qualche costrutto profondamente annidato durante la normale elaborazione.È qui che la cattura e il lancio tornano utili.(Thomas e Hunt, 2001)
Riferimenti
- Grimm, Avdi."Lancia, cattura, alza, salva ... Sono così confuso!" Blog di Ruilearning.Np, 11 luglio 2011.Ragnatela.1 gennaio2012. http://rubylearning.com/blog/2011/07/12/throw-catch-raise-rescue--im-so-confused/.
- Thomas, Dave e Andrew Hunt."Programmazione Ruby." :La guida pragmatica del programmatore.Np, 2001.Ragnatela.29 settembre2015. http://ruby-doc.com/docs/ProgrammingRuby/html/tut_exceptions.html.
https://coderwall.com/p/lhkkug/don-t-confuse-ruby-s-throw-statement-with-raise offre un'eccellente spiegazione che dubito di poter migliorare.Per riassumere, prendo alcuni esempi di codice dal post del blog mentre procedo:
raise
/rescue
sono gli analoghi più vicini althrow
/catch
costrutto con cui hai familiarità da altri linguaggi (o da Pythonraise
/except
).Se hai riscontrato una condizione di errore e lo farestithrow
sopra in un'altra lingua, dovrestiraise
in Rubino.Quello di Ruby
throw
/catch
ti consente di interrompere l'esecuzione e risalire lo stack cercando acatch
(Piaceraise
/rescue
lo fa), ma non è realmente pensato per condizioni di errore.Dovrebbe essere usato raramente, ed è lì solo per quando "salisci lo stack finché non trovi un corrispondente".catch
" il comportamento ha senso per un algoritmo che stai scrivendo, ma non avrebbe senso pensare althrow
come corrispondente ad una condizione di errore.A cosa serve il "prendi e lancia" in Ruby? offre alcuni suggerimenti sugli usi piacevoli di
throw
/catch
costruire.
Le differenze comportamentali concrete tra loro includono:
rescue Foo
salverà le istanze diFoo
comprese le sottoclassi diFoo
.catch(foo)
catturerà solo lo stesso oggetto,Foo
.Non solo non puoi passarecatch
un nome di classe per catturarne le istanze, ma non eseguirà nemmeno confronti di uguaglianza.Ad esempiocatch("foo") do throw "foo" end
ti darà un
UncaughtThrowError: uncaught throw "foo"
(o unArgumentError
nelle versioni di Ruby precedenti alla 2.2)È possibile elencare più clausole di salvataggio...
begin do_something_error_prone rescue AParticularKindOfError # Insert heroism here. rescue write_to_error_log raise end
mentre multiplo
catch
devono essere nidificati...catch :foo do catch :bar do do_something_that_can_throw_foo_or_bar end end
Uno nudo
rescue
è equivalente arescue StandardError
ed è un costrutto idiomatico.Un "nudo".catch
", Piacecatch() {throw :foo}
, non catturerà mai nulla e non dovrebbe essere utilizzato.