В Ruby есть два разных механизма исключений: Throw / Catch и Raise / Rescue.
Почему у нас есть два?
Когда вы должны использовать один, а не другой?
В Ruby есть два разных механизма исключений: Throw / Catch и Raise / Rescue.
Почему у нас есть два?
Когда вы должны использовать один, а не другой?
Ответы:
Я думаю, что http://hasno.info/ruby-gotchas-and-caveats имеет достойное объяснение разницы:
ловить / бросать не то же самое, что поднимать / спасать. catch / throw позволяет вам быстро выходить из блоков обратно в точку, где для определенного символа определена ловушка, повышение аварийного восстановления - это реальная вещь обработки исключений, включающая объект Exception.
raiseэто очень дорого. throwне является. Думайте об throwиспользовании, gotoчтобы выйти из цикла.
raise, fail, rescueИ ensureручки ошибки , также известный как исключенияthrowи catchявляются управление потокомВ отличие от других языков, throw и catch Ruby не используются для исключений. Вместо этого они предоставляют способ прекратить выполнение на ранней стадии, когда не требуется никакой дальнейшей работы. (Grimm, 2011)
Завершение одного уровня управления потоком, как whileцикл, может быть сделано с помощью простого return. Завершение многих уровней потока управления, например, вложенного цикла, может быть выполнено с помощью throw.
Несмотря на то, что механизм исключений при поднятии и спасении отлично подходит для отказа от выполнения, когда что-то идет не так, иногда приятно иметь возможность выпрыгнуть из глубоко вложенной конструкции во время обычной обработки. Это где ловить и бросать пригодится. (Томас и Хант, 2001)
https://coderwall.com/p/lhkkug/don-t-confuse-ruby-s-throw-statement-with-raise предлагает отличное объяснение, которое, я сомневаюсь, смогу улучшить. Подводя итог, прокалывая некоторые примеры кода из поста в блоге, я иду:
raise/ rescueЯвляются ближайшими аналогами к throw/ catchпостроить вы знакомы с других языков (или на языке Python raise/ except). Если вы столкнулись с ошибкой, и вы throwперешли на другой язык, вы должны сделать это raiseв Ruby.
Ruby's 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
в то время как несколько catches должны быть вложены ...
catch :foo do
catch :bar do
do_something_that_can_throw_foo_or_bar
end
endГолый rescueэквивалент rescue StandardErrorи идиоматическая конструкция. «Голый catch», вроде бы catch() {throw :foo}, никогда ничего не поймает и не должен использоваться.
gotoв C / C ++, как упомянул @docwhat, Java пометил break и continue . (У Питона также есть отклоненное предложение для этого.)