Jaka jest różnica między Raising Exceptions a Throwing Exceptions w Rubim?


167

Ruby ma dwa różne mechanizmy wyjątków: rzut / złapanie i podnieś / ratunek.

Dlaczego mamy dwa?

Kiedy należy używać jednego, a kiedy drugiego?


„Wyjście z zagnieżdżonych pętli” jest powszechną potrzebą w wielu językach programowania. Oprócz gotow C / C ++, jak wspomniał @docwhat, Java oznaczyła przerwę i kontynuację . (Python również ma odrzuconą propozycję .)
Franklin Yu

Odpowiedzi:


104

Myślę, że http://hasno.info/ruby-gotchas-and-caveats ma przyzwoite wyjaśnienie różnicy:

złapanie / rzut to nie to samo, co podbicie / uwolnienie. catch / throw pozwala szybko wyjść z bloków z powrotem do punktu, w którym złapanie jest zdefiniowane dla określonego symbolu, podniesienie ratunku to prawdziwa obsługa wyjątków związana z obiektem Exception.


1
Ciekawostki ... Czytam to z iPada, więc nie mogę przetestować ich w 1.9, ale niektóre z tych pułapek nie są już aktualne w ostatnich wersjach Ruby, prawda?
Denis de Bernardy

12
Warto też wiedzieć: raisejest bardzo drogi. thrownie jest. Pomyśl o throwużyciu, gotoaby wyjść z pętli.
docwhat

4
@Denis O jakich pułapkach masz na myśli?
docwhat

1
Link jest uszkodzony!
morhook

Zapoznaj się z rubinowym rzutem i wydajnością, aby dowiedzieć się więcej o różnicy w wydajności.
Franklin Yu

109
  • raise, fail, rescueOraz ensureuchwyt błędy , znany także jako wyjątki
  • throwi catchsterowania przepływem

W przeciwieństwie do innych języków, rzut i złapanie Rubiego nie są używane do wyjątków. Zamiast tego zapewniają sposób na wcześniejsze zakończenie wykonywania, gdy nie są potrzebne żadne dalsze prace. (Grimm, 2011)

Zakończenie pojedynczego poziomu przepływu sterowania, takiego jak whilepętla, można wykonać za pomocą prostego return. Można zakończyć wiele poziomów przepływu sterowania, na przykład pętlę zagnieżdżoną throw.

Chociaż wyjątkowy mechanizm podnoszenia i ratowania świetnie nadaje się do porzucania wykonywania, gdy coś pójdzie nie tak, czasami dobrze jest móc wyskoczyć z jakiejś głęboko zagnieżdżonej konstrukcji podczas normalnego przetwarzania. Tutaj przydaje się łapanie i rzucanie. (Thomas i Hunt, 2001)

Bibliografia

  1. Grimm, Avdi. „Rzuć, łap, podnieś, ratuj… Jestem taki zdezorientowany!” Blog RubyLearning. Np, 11 lipca 2011 r. Internet. 1 stycznia 2012. . Http://rubylearning.com/blog/2011/07/12/throw-catch-raise-rescue--im-so-confused/ .
  2. Thomas, Dave i Andrew Hunt. „Programming Ruby”. : Pragmatyczny przewodnik programisty. Np, 2001. Sieć. 29 września 2015 r . Http://ruby-doc.com/docs/ProgrammingRuby/html/tut_exceptions.html .

2
Avdi nie wygląda tak, jak brzmi w podcastach.
hrdwdmrbl

2
Wydaje się, że link Ruby Learning nie działa. Oto kolejny wpis na blogu, w którym omówiono różnice: danielchangnyc.github.io/blog/2013/10/23/throw-raise
Dennis

Zabawne, rubylearning.com uważa, że ​​artykuł Avdiego wciąż tam jest . Myślę, że dlatego kopiujemy rzeczy do SO, więc nie zostaną utracone!
Jared Beck

21

https://coderwall.com/p/lhkkug/don-t-confuse-ruby-s-throw-statement-with-raise oferuje doskonałe wyjaśnienie, w które wątpię, czy mogę to poprawić. Podsumowując, po drodze wykrywam kilka przykładów kodu z posta na blogu:

  1. raise/ rescuesą najbliższymi odpowiednikami konstrukcji throw/, catchktórą znasz z innych języków (lub raise/ except). Jeśli napotkałeś warunek błędu i chciałbyś throwgo pokonać w innym języku, powinieneś raisew Rubim.

  2. Ruby's throw/ catchpozwala przerwać wykonywanie i wspiąć się na stos w poszukiwaniu catch(jak raise/ rescuerobi), ale tak naprawdę nie jest przeznaczony do warunków błędu. Powinien być używany rzadko i jest używany tylko wtedy, gdy zachowanie „idź po stosie, aż znajdziesz odpowiednie catch” ma sens dla algorytmu, który piszesz, ale nie miałoby sensu myśleć o nim throwjako o błędzie stan: schorzenie.

    Do czego służy metoda łapania i rzucania w języku Ruby? oferuje kilka sugestii dotyczących ładnych zastosowań konstrukcji throw/ catch.

Konkretne różnice w zachowaniu między nimi obejmują:

  • rescue Foouratuje przypadki Foowłączania podklas Foo. catch(foo)złapie tylko ten sam obiekt,Foo . Nie tylko nie możesz przekazać catchnazwy klasy, aby złapać jej instancje, ale nawet nie będzie robić porównań równości. Na przykład

    catch("foo") do
      throw "foo"
    end

    da ci UncaughtThrowError: uncaught throw "foo"(lub an ArgumentErrorw wersjach Rubiego starszych niż 2.2)

  • Można wymienić wiele klauzul ratunkowych ...

    begin
      do_something_error_prone
    rescue AParticularKindOfError
      # Insert heroism here.
    rescue
      write_to_error_log
      raise
    end

    podczas gdy wiele catches musi być zagnieżdżonych ...

    catch :foo do
      catch :bar do
        do_something_that_can_throw_foo_or_bar
      end
    end
  • Bose rescuejest odpowiednikiem rescue StandardErrori jest konstruktem idiomatycznym. Na przykład „goły catchcatch() {throw :foo}nigdy niczego nie złapie i nie powinien być używany.


Dobre wyjaśnienie, ale nasuwa pytanie, dlaczego u licha mieliby zaprojektować podniesienie w rubin = rzut w innym języku. a następnie uwzględnij także rzut, ale to! = rzut w innych językach. Nie widzę tam ich oryginalnej logiki
wired00

@ wired00 ( wzruszając ramionami ) Zgadzam się, że wydaje się to dość ekscentryczne w porównaniu z innymi popularnymi obecnie językami.
Mark Amery,

2
@ wired00: Od czasu pierwszych eksperymentów z ustrukturyzowaną obsługą błędów w latach sześćdziesiątych nazywano to „zgłaszaniem” wyjątku. Nazywa się to „zgłaszaniem” wyjątku w nowatorskich artykułach, w których wynaleziono nowoczesną formę obsługi wyjątków. „podniesienie” wyjątku w Lisps i Smalltalks, które były jednymi z głównych inspiracji dla Rubiego, i nazywa się to „podniesieniem” wyjątku lub „podniesieniem” przerwania w sprzęcie, gdzie koncepcja istniała jeszcze przed koncepcją „programowania” język ”istniał. Pytanie powinno raczej brzmieć: dlaczego te inne języki to zmieniły?
Jörg W Mittag,

@MarkAmery: Pamiętaj, że wiele z tych „innych popularnych języków” jest młodszych od Rubiego lub przynajmniej współcześnie. Zatem pytanie powinno raczej brzmieć: dlaczego te inne języki nie są zgodne z Rubim (i Smalltalk i Lisp oraz sprzętem i literaturą).
Jörg W Mittag,

@ JörgWMittag Interesujące - zainspirowałeś mnie do przeprowadzenia krótkich badań historycznych. C ++ miał pojęcie o „rzucaniu” wyjątku na wiele lat przed pojawieniem się Rubiego, a według english.stackexchange.com/a/449209/73974 termin ten faktycznie sięga lat 70-tych ... więc myślę, że nadal możemy krytykować Ruby za przyjmowanie ustalonej terminologii i używanie jej do oznaczania czegoś zupełnie innego.
Mark Amery,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.