«Выход из вложенных циклов» является распространенной потребностью во многих языках программирования. Помимо того, что gotoв C / C ++, как упомянул @docwhat, Java пометил break и continue . (У Питона также есть отклоненное предложение для этого.)
ловить / бросать не то же самое, что поднимать / спасать. catch / throw позволяет вам быстро выходить из блоков обратно в точку, где для определенного символа определена ловушка, повышение аварийного восстановления - это реальная вещь обработки исключений, включающая объект Exception.
raise, fail, rescueИ ensureручки ошибки , также известный как исключения
throwи catchявляются управление потоком
В отличие от других языков, throw и catch Ruby не используются для исключений. Вместо этого они предоставляют способ прекратить выполнение на ранней стадии, когда не требуется никакой дальнейшей работы. (Grimm, 2011)
Завершение одного уровня управления потоком, как whileцикл, может быть сделано с помощью простого return. Завершение многих уровней потока управления, например, вложенного цикла, может быть выполнено с помощью throw.
Несмотря на то, что механизм исключений при поднятии и спасении отлично подходит для отказа от выполнения, когда что-то идет не так, иногда приятно иметь возможность выпрыгнуть из глубоко вложенной конструкции во время обычной обработки. Это где ловить и бросать пригодится. (Томас и Хант, 2001)
raise/ rescueЯвляются ближайшими аналогами к throw/ catchпостроить вы знакомы с других языков (или на языке Python raise/ except). Если вы столкнулись с ошибкой, и вы throwперешли на другой язык, вы должны сделать это raiseв Ruby.
Ruby's throw/ catchпозволяет вам прервать выполнение и подняться по стеку в поисках catch(как raise/ rescueделает), но на самом деле не предназначено для ошибок. Его следует использовать редко, и это только для случая, когда catchповедение «подниматься по стеку, пока вы не найдете соответствующее » имеет смысл для алгоритма, который вы пишете, но не имеет смысла думать о том, throwчто оно соответствует ошибке состояние.
Конкретные поведенческие различия между ними включают в себя:
rescue Fooспасет случаи Fooвключения подклассов Foo. catch(foo)будет ловить только тот же объектFoo . Вы не только не можете передать catchимя класса, чтобы поймать его экземпляры, но и не будет даже сравнения на равенство. Например
Несколько пунктов спасения могут быть перечислены ...
begin
do_something_error_prone
rescueAParticularKindOfError# 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
endend
Голый rescueэквивалент rescue StandardErrorи идиоматическая конструкция. «Голый catch», вроде бы catch() {throw :foo}, никогда ничего не поймает и не должен использоваться.
Хорошее объяснение, но напрашивается вопрос, с какой стати они спроектируют рейз в рубине = метание на другом языке. а затем также включить throw но it! = throw на других языках. Я не вижу их оригинальной логики там
wired00
@ wired00 ( пожимает плечами .) Я согласен, что это кажется довольно эксцентричным по сравнению с другими популярными языками сегодня.
Марк Эмери
2
@ wired00: С самого первого эксперимента по обработке структурированных ошибок в 1960-х годах его называли «поднятием» исключения. В оригинальных статьях, которые изобрели современную форму обработки исключений, это называется «поднятием» исключения. «Возбуждение» исключения в Lisps и Smalltalks, которые были одними из основных источников вдохновения для Ruby, и это называется «поднятие» исключения или «поднятие» аппаратного прерывания, где эта концепция существовала еще до концепции «программирования». язык "существовал. Вопрос скорее должен быть: почему эти другие языки изменили это?
Йорг Миттаг
@MarkAmery: Помните, что многие из этих «других популярных языков» моложе Ruby или, по крайней мере, современны. Таким образом, вопрос должен быть: почему эти другие языки не следуют Ruby (Smalltalk, Lisp, аппаратное обеспечение и литература).
Йорг Миттаг
@ JörgWMittag Интересно - вы вдохновили меня на небольшое историческое исследование. В C ++ было понятие «выбрасывать» исключение за годы до появления Ruby, и, согласно английскому слову .stackexchange.com / a / 449209 / 73974, термин фактически восходит к 70-м годам ... поэтому я думаю, что мы все еще будем критиковать Ruby за взятие установленной терминологии и использование ее для обозначения чего-то совершенно другого.
goto
в C / C ++, как упомянул @docwhat, Java пометил break и continue . (У Питона также есть отклоненное предложение для этого.)Ответы:
Я думаю, что http://hasno.info/ruby-gotchas-and-caveats имеет достойное объяснение разницы:
источник
raise
это очень дорого.throw
не является. Думайте обthrow
использовании,goto
чтобы выйти из цикла.raise
,fail
,rescue
Иensure
ручки ошибки , также известный как исключенияthrow
иcatch
являются управление потокомЗавершение одного уровня управления потоком, как
while
цикл, может быть сделано с помощью простогоreturn
. Завершение многих уровней потока управления, например, вложенного цикла, может быть выполнено с помощьюthrow
.Ссылки
источник
https://coderwall.com/p/lhkkug/don-t-confuse-ruby-s-throw-statement-with-raise предлагает отличное объяснение, которое, я сомневаюсь, смогу улучшить. Подводя итог, прокалывая некоторые примеры кода из поста в блоге, я иду:
raise
/rescue
Являются ближайшими аналогами кthrow
/catch
построить вы знакомы с других языков (или на языке Pythonraise
/except
). Если вы столкнулись с ошибкой, и выthrow
перешли на другой язык, вы должны сделать этоraise
в Ruby.Ruby's
throw
/catch
позволяет вам прервать выполнение и подняться по стеку в поискахcatch
(какraise
/rescue
делает), но на самом деле не предназначено для ошибок. Его следует использовать редко, и это только для случая, когдаcatch
поведение «подниматься по стеку, пока вы не найдете соответствующее » имеет смысл для алгоритма, который вы пишете, но не имеет смысла думать о том,throw
что оно соответствует ошибке состояние.Для чего в Ruby используется ловить и бросать? предлагает несколько советов по хорошему использованию конструкции
throw
/catch
.Конкретные поведенческие различия между ними включают в себя:
rescue Foo
спасет случаиFoo
включения подклассовFoo
.catch(foo)
будет ловить только тот же объектFoo
. Вы не только не можете передатьcatch
имя класса, чтобы поймать его экземпляры, но и не будет даже сравнения на равенство. Напримердаст вам
UncaughtThrowError: uncaught throw "foo"
(илиArgumentError
в версиях Ruby до 2.2)Несколько пунктов спасения могут быть перечислены ...
в то время как несколько
catch
es должны быть вложены ...Голый
rescue
эквивалентrescue StandardError
и идиоматическая конструкция. «Голыйcatch
», вроде быcatch() {throw :foo}
, никогда ничего не поймает и не должен использоваться.источник