В чем разница между вызовом исключений и созданием исключений в Ruby?
Вопрос
Ruby имеет два разных механизма исключений:Бросок/Поймать и Поднимать/Спасать.
Почему у нас двое?
Когда следует использовать одно, а не другое?
Решение
Я думаю http://hasno.info/ruby-gotchas-and-caveats имеет достойное объяснение разницы:
поймать/бросить – это не то же самое, что поднять/спасти.catch/throw позволяет вам быстро выйти из блоков обратно в точку, где catch определен для определенного символа, а поднять спасение - это настоящая обработка исключений, включающая объект Exception.
Другие советы
raise
,fail
,rescue
, иensure
ручка ошибки, также известен как исключенияthrow
иcatch
являются поток управления
В отличие от других языков, бросок и улов Руби не используются для исключений.Вместо этого они предоставляют способ прекратить исполнение на ранней стадии, когда дальнейшая работа не требуется.(Гримм, 2011)
Завершение одного уровня потока управления, например while
цикл, можно сделать с помощью простого return
.Завершение многих уровней потока управления, например вложенного цикла, можно выполнить с помощью throw
.
Хотя механизм исключений подъема и восстановления отлично подходит для прекращения выполнения, когда что-то идет не так, иногда полезно иметь возможность выпрыгнуть из какой-то глубоко вложенной конструкции во время обычной обработки.Вот тут-то и пригодятся ловля и бросок.(Томас и Хант, 2001 г.)
Рекомендации
- Гримм, Авди."Брось, поймай, поднимай, спаси ... я так запутался!" Блог Rubylearning.Н.п., 11 июля 2011 г.Веб.1 янв.2012. http://rubylearning.com/blog/2011/07/12/throw-catch-raise-rescue--im-so-confused/.
- Томас, Дэйв и Эндрю Хант.«Программирование рубины». :Руководство прагматичного программиста.Н.П., 2001.Веб.29 сент.2015. http://ruby-doc.com/docs/ProgrammingRuby/html/tut_Exceptions.html.
https://coderwall.com/p/lhkkug/don-t-confuse-ruby-s-throw-statement-with-raise предлагает превосходное объяснение, которое я сомневаюсь, что смогу улучшить.Подводя итог, я по ходу дела беру несколько примеров кода из поста в блоге:
raise
/rescue
являются ближайшими аналогамиthrow
/catch
конструкцию, с которой вы знакомы по другим языкам (или Pythonraise
/except
).Если вы столкнулись с ошибкой и хотитеthrow
над этим на другом языке, вам следуетraise
в Руби.Руби
throw
/catch
позволяет прервать выполнение и подняться вверх по стеку в поискахcatch
(нравитьсяraise
/rescue
делает), но на самом деле не предназначен для ошибок.Его следует использовать редко, и только тогда, когда «идите вверх по стеку, пока не найдете соответствующее».catch
«Поведение имеет смысл для алгоритма, который вы пишете, но не имеет смысла думать оthrow
как соответствующее состоянию ошибки.Для чего в Ruby используются ловля и бросок? предлагает несколько советов по хорошему использованию
throw
/catch
построить.
Конкретные поведенческие различия между ними включают:
rescue Foo
спасет экземплярыFoo
включая подклассыFoo
.catch(foo)
только поймаю тот же объект,Foo
.Мало того, что ты не можешь пройтиcatch
имя класса, чтобы перехватывать его экземпляры, но оно даже не выполняет сравнения на равенство.Напримерcatch("foo") do throw "foo" end
даст вам
UncaughtThrowError: uncaught throw "foo"
(илиArgumentError
в версиях Ruby до 2.2)Можно перечислить несколько статей о спасении...
begin do_something_error_prone rescue AParticularKindOfError # Insert heroism here. rescue write_to_error_log raise end
в то время как несколько
catch
это должно быть вложенным...catch :foo do catch :bar do do_something_that_can_throw_foo_or_bar end end
Голый
rescue
эквивалентноrescue StandardError
и является идиоматической конструкцией.«Голыйcatch
", нравитьсяcatch() {throw :foo}
, никогда ничего не поймает и не должен использоваться.