В 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
в то время как несколько catch
es должны быть вложены ...
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 . (У Питона также есть отклоненное предложение для этого.)