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.
raise
jest bardzo drogi. throw
nie jest. Pomyśl o throw
użyciu, goto
aby wyjść z pętli.
raise
, fail
, rescue
Oraz ensure
uchwyt błędy , znany także jako wyjątkithrow
i catch
są 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 while
pę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
/ rescue
są najbliższymi odpowiednikami konstrukcji throw
/, catch
którą znasz z innych języków (lub raise
/ except
). Jeśli napotkałeś warunek błędu i chciałbyś throw
go pokonać w innym języku, powinieneś raise
w Rubim.
Ruby's throw
/ catch
pozwala przerwać wykonywanie i wspiąć się na stos w poszukiwaniu catch
(jak raise
/ rescue
robi), 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 throw
jako 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 Foo
uratuje przypadki Foo
włączania podklas Foo
. catch(foo)
złapie tylko ten sam obiekt,Foo
. Nie tylko nie możesz przekazać catch
nazwy 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 ArgumentError
w 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 catch
es musi być zagnieżdżonych ...
catch :foo do
catch :bar do
do_something_that_can_throw_foo_or_bar
end
end
Bose rescue
jest odpowiednikiem rescue StandardError
i jest konstruktem idiomatycznym. Na przykład „goły catch
” catch() {throw :foo}
nigdy niczego nie złapie i nie powinien być używany.
goto
w C / C ++, jak wspomniał @docwhat, Java oznaczyła przerwę i kontynuację . (Python również ma odrzuconą propozycję .)