Я недавно начал программировать на Ruby, и я смотрю на обработку исключений.
Мне было интересно, ensure
был ли Ruby эквивалент finally
в C #? Должен ли я иметь:
file = File.open("myFile.txt", "w")
begin
file << "#{content} \n"
rescue
#handle the error here
ensure
file.close unless file.nil?
end
или я должен это сделать?
#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
Вам ensure
звонят, несмотря ни на что, даже если исключение не выдвинуто?
ruby-on-rails
ruby
exception
exception-handling
error-handling
Ллойд Пауэлл
источник
источник
begin
блока.Ответы:
Да,
ensure
гарантирует, что код всегда оценивается. Вот почему это называетсяensure
. Таким образом, это эквивалентно Java и C #finally
.Общий поток
begin
/rescue
/else
/ensure
/end
выглядит так:Вы можете оставить
rescue
,ensure
илиelse
. Вы также можете пропустить переменные, в этом случае вы не сможете проверить исключение в своем коде обработки исключений. (Ну, вы всегда можете использовать глобальную переменную исключения для доступа к последнему исключению, которое было сгенерировано, но это немного странно.) И вы можете пропустить класс исключений, и в этом случае все исключения, наследуемые от,StandardError
будут перехвачены. (Пожалуйста , обратите внимание , что это не означает , что все исключения пойманы, потому что есть исключения , которые являются экземплярами ,Exception
но неStandardError
. В основном очень серьезные исключения , которые ставят под угрозу целостность программы , такие какSystemStackError
,NoMemoryError
,SecurityError
,NotImplementedError
,LoadError
,SyntaxError
,ScriptError
,Interrupt
,SignalException
илиSystemExit
.)Некоторые блоки образуют неявные блоки исключений. Например, определения методов неявно являются также блоками исключений, поэтому вместо записи
ты пишешь просто
или
То же самое относится к
class
определениям иmodule
определениям.Однако в конкретном случае, о котором вы спрашиваете, на самом деле существует гораздо лучшая идиома. В общем, когда вы работаете с каким-то ресурсом, который необходимо очистить в конце, вы делаете это, передавая блок методу, который выполняет всю очистку за вас. Это похоже на
using
блок в C #, за исключением того, что Ruby на самом деле достаточно мощный, чтобы вам не приходилось ждать, когда первосвященники Microsoft спустятся с горы и милостиво поменяют свой компилятор для вас. В Ruby вы можете просто реализовать это самостоятельно:И что вы знаете: это уже доступно в основной библиотеке как
File.open
. Но это общий шаблон, который вы также можете использовать в своем собственном коде для реализации любого вида очистки ресурсов (какusing
в C #) или транзакций или чего-либо еще, о чем вы могли подумать.Единственный случай, когда это не работает, если приобретение и выпуск ресурса распределены по разным частям программы. Но если он локализован, как в вашем примере, вы можете легко использовать эти блоки ресурсов.
Кстати, в современном C #
using
это на самом деле излишне, потому что вы можете реализовать блоки ресурсов в стиле Ruby самостоятельно:источник
ensure
операторы выполняются последними, они не являются возвращаемым значением.ensure
позвонят, несмотря ни на что».К вашему сведению, даже если исключение повторно вызывается в
rescue
разделе,ensure
блок будет выполнен до того, как выполнение кода продолжится до следующего обработчика исключений. Например:источник
Если вы хотите убедиться, что файл закрыт, вы должны использовать блочную форму
File.open
:источник
Да,
ensure
называется при любых обстоятельствах. Для получения дополнительной информации см. « Исключения, поймать и выбросить » книги по программированию на Ruby и выполнить поиск «обеспечить».источник
Да,
ensure
гарантирует, что он запускается каждый раз, поэтому вам не нужноfile.close
вbegin
блоке.Кстати, хороший способ проверить это сделать:
Вы можете проверить, будет ли "========= внутри блока гарантированности" распечатываться при возникновении исключения. Затем вы можете закомментировать оператор, который вызывает ошибку, и посмотреть, выполняется ли
ensure
оператор, посмотрев, распечатано ли что-нибудь.источник
Вот почему нам нужно
ensure
:источник
Да,
ensure
вродеfinally
гарантирует, что блок будет выполнен . Это очень полезно для обеспечения защиты критических ресурсов, например, закрытия дескриптора файла при ошибке или освобождения мьютекса.источник
File.open
часть НЕ находится внутри блока начала-обеспечения. Толькоfile.close
есть, но этого недостаточно.