Qual'è la differenza tra Raising Exceptions vs Throwing Exceptions in Ruby?


Risposte:


104

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.


1
Curioso da sapere ... Leggere questo da un iPad, quindi non è possibile testarli in 1.9, ma alcuni di quei gotcha non sono più validi nelle recenti versioni di ruby, giusto?
Denis de Bernardy,

12
Vale anche la pena sapere: raiseè molto costoso. thrownon è. Pensa a throwcome usare gotoper uscire da un ciclo.
docwhat il

4
@Denis A quali gotcha ti riferisci?
docwhat,

1
Il collegamento è interrotto!
Morhook,

Vedi ruby catch-throw ed efficienza per capire di più sulla differenza di prestazioni.
Franklin Yu,

110
  • raise, fail, rescue, E ensuremaniglia errori , noti anche come eccezioni
  • throwe catchsono flusso di controllo

A 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)

Riferimenti

  1. Grimm, Avdi. "Lancia, cattura, solleva, salva ... Sono così confuso!" Blog di RubyLearning. Np, 11 luglio 2011. Web. 1 gennaio 2012. http://rubylearning.com/blog/2011/07/12/throw-catch-raise-rescue--im-so-confused/ .
  2. Thomas, Dave e Andrew Hunt. "Programmazione di Ruby." : La guida del programmatore pragmatico. Np, 2001. Web. 29 settembre 2015. http://ruby-doc.com/docs/ProgrammingRuby/html/tut_exceptions.html .

2
Avdi non sembra che suoni nei podcast.
hrdwdmrbl,

2
Il collegamento di Ruby Learning non sembra funzionare. Ecco un altro post sul blog che discute le differenze: danielchangnyc.github.io/blog/2013/10/23/throw-raise
Dennis

Divertente, rubylearning.com pensa che l'articolo di Avdi sia ancora lì . Immagino sia per questo che copiamo le cose su SO, quindi non andranno perse!
Jared Beck,

21

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:

  1. 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.

  2. 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.


Buona spiegazione ma fa sorgere la domanda, perché mai progettare rilanciare in ruby ​​= lanciare in un'altra lingua. e poi includi anche butta ma! = lancia in altre lingue. Non riesco a vedere la loro logica originale lì
cablata il

@ wired00 (Shrug.) Sono d'accordo che sembra piuttosto eccentrico rispetto ad altre lingue popolari oggi.
Mark Amery,

2
@ wired00: è stato chiamato "sollevare" un'eccezione sin dai primi esperimenti con la gestione strutturata degli errori negli anni '60, si chiama "sollevare" un'eccezione negli articoli fondamentali che hanno inventato la forma moderna di gestione delle eccezioni, si chiama "sollevare" un'eccezione in Lisps e Smalltalks, che sono state alcune delle principali ispirazioni di Ruby, e si chiama "sollevare" un'eccezione o "sollevare" un interrupt in hardware, dove il concetto esisteva anche prima del concetto di "programmazione" la lingua "esisteva. La domanda dovrebbe piuttosto essere: perché quelle altre lingue hanno cambiato questo?
Jörg W Mittag,

@MarkAmery: ricorda che molte di quelle "altre lingue popolari" sono più giovani di Ruby o almeno contemporanee. Quindi, la domanda dovrebbe piuttosto essere: perché quelle altre lingue non hanno seguito Ruby (e Smalltalk, Lisp, hardware e letteratura).
Jörg W Mittag,

@ JörgWMittag Interessante: mi hai ispirato a fare una piccola ricerca storica. Il C ++ aveva l'idea di "lanciare" un'eccezione anni prima che arrivasse Ruby, e per english.stackexchange.com/a/449209/73974 il termine in realtà risale agli anni '70 ... quindi penso che dobbiamo ancora criticare Ruby per prendere una terminologia consolidata e usarla per significare qualcosa di completamente diverso.
Mark Amery,
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.