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. throw
non è. Pensa a throw
come usare goto
per uscire da un ciclo.
raise
, fail
, rescue
, E ensure
maniglia errori , noti anche come eccezionithrow
e catch
sono 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 while
loop, 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
/ rescue
sono gli analoghi più vicini al costrutto throw
/ con cui catch
hai familiarità con altre lingue (o con Python raise
/ except
). Se hai riscontrato una condizione di errore e la superassi throw
in un'altra lingua, dovresti trovarla raise
in Ruby.
Ruby throw
/ catch
ti consente di interrompere l'esecuzione e scalare lo stack alla ricerca di catch
(like raise
/ rescue
does), ma non è realmente pensato per condizioni di errore. Dovrebbe essere usato di rado, ed è lì solo per quando il catch
comportamento "cammina nello stack finché non trovi un corrispondente " ha senso per un algoritmo che stai scrivendo, ma non avrebbe senso pensare throw
che corrisponda a un errore condizione.
A cosa serve il pescare e lanciare in Ruby? offre alcuni suggerimenti su piacevoli usi del throw
/ catch
costrutto.
Le differenze comportamentali concrete tra loro includono:
rescue Foo
salverà casi di Foo
inclusione di sottoclassi di Foo
. catch(foo)
prenderà solo lo stesso oggetto,Foo
. Non solo non puoi passare catch
un 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 ArgumentError
in 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ù catch
es devono essere nidificati ...
catch :foo do
catch :bar do
do_something_that_can_throw_foo_or_bar
end
end
Un nudo rescue
equivale a rescue StandardError
ed è un costrutto idiomatico. Un "nudo catch
", come catch() {throw :foo}
, non catturerà mai nulla e non dovrebbe essere usato.
goto
in C / C ++, come accennato da @docwhat, Java ha etichettato break e continue . (Python ha anche una proposta respinta per questo.)