Ostatnio zacząłem programować w Ruby i patrzę na obsługę wyjątków.
Zastanawiałem się, czy ensure
to odpowiednik Rubiegofinally
w C #? Czy powinienem mieć:
file = File.open("myFile.txt", "w")
begin
file << "#{content} \n"
rescue
#handle the error here
ensure
file.close unless file.nil?
end
czy powinienem to zrobić?
#store the file
file = File.open("myFile.txt", "w")
begin
file << "#{content} \n"
file.close
rescue
#handle the error here
ensure
file.close unless file.nil?
end
Czy ensure
zostanie wywołany bez względu na wszystko, nawet jeśli wyjątek nie zostanie zgłoszony?
ruby-on-rails
ruby
exception
exception-handling
error-handling
Lloyd Powell
źródło
źródło
begin
bloku.Odpowiedzi:
Tak,
ensure
zapewnia, że kod jest zawsze analizowany. Dlatego się nazywaensure
. Jest to więc odpowiednik Javy i C #finally
.Ogólny przepływ
begin
/rescue
/else
/ensure
/end
wygląda następująco:Można pominąć
rescue
,ensure
lubelse
. Możesz także pominąć zmienne, w którym to przypadku nie będziesz mógł sprawdzić wyjątku w kodzie obsługi wyjątków. (Cóż, zawsze możesz użyć globalnej zmiennej wyjątku, aby uzyskać dostęp do ostatniego zgłoszonego wyjątku, ale to jest trochę zhackowane.) I możesz pominąć klasę wyjątków, w którym to przypadkuStandardError
wychwycone zostaną wszystkie wyjątki, które dziedziczą . (Należy pamiętać, że to nie oznacza, że wszystkie wyjątki zostały złowione, ponieważ istnieją wyjątki, które są przypadkiException
, ale nieStandardError
. Głównie bardzo poważne wyjątki że kompromis integralność programu, takie jakSystemStackError
,NoMemoryError
,SecurityError
,NotImplementedError
,LoadError
,SyntaxError
,ScriptError
, lubInterrupt
,SignalException
SystemExit
.)Niektóre bloki tworzą niejawne bloki wyjątków. Na przykład definicje metod są domyślnie także blokami wyjątków, więc zamiast pisania
piszesz tylko
lub
To samo dotyczy
class
definicji imodule
definicji.Jednak w konkretnym przypadku, o który pytasz, istnieje o wiele lepszy idiom. Ogólnie rzecz biorąc, gdy pracujesz z jakimś zasobem, który musisz oczyścić na końcu, robisz to, przekazując blok metodzie, która wykonuje za Ciebie całe czyszczenie. Jest podobny do
using
bloku w języku C #, z tym wyjątkiem, że Ruby jest wystarczająco potężny, abyś nie musiał czekać na najwyższych kapłanów Microsoftu, którzy zejdą z góry i łaskawie zmienią dla ciebie kompilator. W Ruby możesz to po prostu zaimplementować:A co wiesz: jest to już dostępne w podstawowej bibliotece jako
File.open
. Ale jest to ogólny wzorzec, którego można również użyć we własnym kodzie, do implementacji wszelkiego rodzaju czyszczenia zasobów (à lausing
w języku C #) lub transakcji lub cokolwiek innego, co możesz wymyślić.Jedyny przypadek, w którym to nie działa, jeśli pozyskiwanie i zwalnianie zasobów jest rozłożone na różne części programu. Ale jeśli jest zlokalizowane, jak w twoim przykładzie, możesz łatwo użyć tych bloków zasobów.
BTW: we współczesnym języku C #
using
jest w rzeczywistości zbędny, ponieważ możesz samodzielnie implementować bloki zasobów w stylu Ruby:źródło
ensure
instrukcje są wykonywane jako ostatnie, nie są one wartością zwracaną.ensure
dzwonię bez względu na wszystko”.Do Twojej wiadomości, nawet jeśli wyjątek zostanie ponownie zgłoszony w
rescue
sekcji,ensure
blok zostanie wykonany, zanim wykonanie kodu przejdzie do następnego modułu obsługi wyjątków. Na przykład:źródło
Jeśli chcesz upewnić się, że plik jest zamknięty, powinieneś użyć formy blokowej
File.open
:źródło
Tak,
ensure
jest wywoływany w każdych okolicznościach. Aby uzyskać więcej informacji, zobacz „ Wyjątki, wyłapywanie i rzucanie ” książki Ruby Programowanie i wyszukaj słowo „zapewnij”.źródło
Tak,
ensure
ZAPEWNIA, że jest uruchamiany za każdym razem, więc nie potrzebujesz gofile.close
wbegin
bloku.Nawiasem mówiąc, dobrym sposobem na przetestowanie jest wykonanie:
Możesz sprawdzić, czy „========= wewnątrz upewnij się, że blok” zostanie wydrukowany, gdy wystąpi wyjątek. Następnie możesz skomentować instrukcję, która powoduje błąd, i sprawdzić, czy
ensure
instrukcja jest wykonywana, sprawdzając, czy coś zostanie wydrukowane.źródło
Dlatego potrzebujemy
ensure
:źródło
Tak,
ensure
podobnie jakfinally
gwarancje, że blok zostanie wykonany . Jest to bardzo przydatne do zapewnienia ochrony krytycznych zasobów, np. Zamknięcia dojścia do pliku w przypadku błędu lub zwolnienia muteksu.źródło
File.open
część NIE znajduje się w bloku początkowym. Tylkofile.close
jest, ale to nie wystarczy.