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?
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?
Odpowiedzi:
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.
raisejest bardzo drogi. thrownie jest. Pomyśl o throwużyciu, gotoaby wyjść z pętli.
raise, fail, rescueOraz ensureuchwyt błędy , znany także jako wyjątkithrowi catchsą sterowania przepływemW 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)
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:
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.
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
endBose rescuejest odpowiednikiem rescue StandardErrori jest konstruktem idiomatycznym. Na przykład „goły catch” catch() {throw :foo}nigdy niczego nie złapie i nie powinien być używany.
gotow C / C ++, jak wspomniał @docwhat, Java oznaczyła przerwę i kontynuację . (Python również ma odrzuconą propozycję .)