Ruby ha due diversi meccanismi di eccezione: Throw / Catch e Raise / Rescue.
Perché ne abbiamo due?
Quando dovresti usare l'uno e non l'altro?
Ruby ha due diversi meccanismi di eccezione: Throw / Catch e Raise / Rescue.
Perché ne abbiamo due?
Quando dovresti usare l'uno e non l'altro?
Risposte:
Penso che http://hasno.info/ruby-gotchas-and-caveats abbia una spiegazione decente della differenza:
catturare / lanciare non sono gli stessi di rilancio / salvataggio. catch / throw ti consente di uscire rapidamente dai blocchi in un punto in cui è definito un catch per un simbolo specifico, rilanciare il salvataggio è la vera eccezione che gestisce le cose che coinvolgono l'oggetto Exception.
raiseè molto costoso. thrownon è. Pensa a throwcome usare gotoper uscire da un ciclo.
raise, fail, rescue, E ensuremaniglia errori , noti anche come eccezionithrowe catchsono flusso di controlloA differenza di altre lingue, il lancio e la presa di Ruby non vengono utilizzati per le eccezioni. Forniscono invece un modo per terminare l'esecuzione in anticipo quando non è necessario ulteriore lavoro. (Grimm, 2011)
Terminare un singolo livello di flusso di controllo, come un whileloop, può essere fatto con un semplice return. È possibile terminare molti livelli del flusso di controllo, come un loop nidificato throw.
Mentre il meccanismo di eccezione di rilancio e salvataggio è ottimo per abbandonare l'esecuzione quando le cose vanno male, a volte è bello poter saltare fuori da un costrutto profondamente annidato durante la normale elaborazione. Qui è dove prendere e lanciare tornano utili. (Thomas and Hunt, 2001)
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, intaccando alcuni esempi di codice dal post del blog mentre vado:
raise/ rescuesono gli analoghi più vicini al costrutto throw/ con cui catchhai familiarità con altre lingue (o con Python raise/ except). Se hai riscontrato una condizione di errore e la superassi throwin un'altra lingua, dovresti trovarla raisein Ruby.
Ruby throw/ catchti consente di interrompere l'esecuzione e scalare lo stack alla ricerca di catch(like raise/ rescuedoes), ma non è realmente pensato per condizioni di errore. Dovrebbe essere usato di rado, ed è lì solo per quando il catchcomportamento "cammina nello stack finché non trovi un corrispondente " ha senso per un algoritmo che stai scrivendo, ma non avrebbe senso pensare throwche corrisponda a un errore condizione.
A cosa serve il pescare e lanciare in Ruby? offre alcuni suggerimenti su piacevoli usi del throw/ catchcostrutto.
Le differenze comportamentali concrete tra loro includono:
rescue Foosalverà casi di Fooinclusione di sottoclassi di Foo. catch(foo)prenderà solo lo stesso oggetto,Foo . Non solo non puoi passare catchun nome di classe per catturarne le istanze, ma non farà nemmeno confronti di uguaglianza. Per esempio
catch("foo") do
throw "foo"
end
ti darà un UncaughtThrowError: uncaught throw "foo"(o un ArgumentErrorin 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 più catches devono essere nidificati ...
catch :foo do
catch :bar do
do_something_that_can_throw_foo_or_bar
end
end
Un nudo rescueequivale a rescue StandardErrored è un costrutto idiomatico. Un "nudo catch", come catch() {throw :foo}, non catturerà mai nulla e non dovrebbe essere usato.
gotoin C / C ++, come accennato da @docwhat, Java ha etichettato break e continue . (Python ha anche una proposta respinta per questo.)