В чем разница между повышением исключений и созданием исключений в Ruby? - PullRequest
153 голосов
/ 09 сентября 2008

В Ruby есть два разных механизма исключений: Бросок / Поймать и Поднять / Спасти.

Почему у нас два?

Когда вы должны использовать один, а не другой?

Ответы [ 3 ]

100 голосов
/ 09 сентября 2008

Я думаю http://hasno.info/ruby-gotchas-and-caveats имеет достойное объяснение разницы:

поймать / бросить не то же самое, что поднять / спасти. catch / throw позволяет вам быстро выходить из блоков обратно в точку, где для определенного символа определен улов, повышение аварийного восстановления - это реальная вещь обработки исключений, включающая объект Exception.

96 голосов
/ 01 января 2012
  • raise, fail, rescue и ensure обрабатывают ошибки , также известные как исключения
  • throw и catch являются потоком управления

В отличие от других языки, throw и catch Ruby не используются для исключений. Вместо этого они предоставляют способ прекратить выполнение рано, когда нет необходима дальнейшая работа. (Grimm, 2011)

Завершение одного уровня потока управления, например, цикла while, можно выполнить с помощью простого return. Завершение многих уровней потока управления, например, вложенного цикла, можно выполнить с помощью throw.

Несмотря на то, что механизм исключений при поднятии и спасении отлично подходит для отказа от выполнения, когда что-то идет не так, иногда приятно иметь возможность выпрыгнуть из какой-то глубоко вложенной конструкции во время обычной обработки. Это где ловить и бросать пригодится. (Томас и Хант, 2001)

Ссылки

  1. Гримм, Авди. «Брось, поймай, поднимись, спаси… Я в замешательстве!» Блог RubyLearning. Н.П., 11 июля 2011 года. Веб. 1 января 2012 года. http://rubylearning.com/blog/2011/07/12/throw-catch-raise-rescue--im-so-confused/.
  2. Томас, Дейв и Эндрю Хант. «Программирование на Ruby». : Прагматическое Руководство программиста. N.p., 2001. Web. 29 сентября 2015 года. http://ruby -doc.com / docs / ProgrammingRuby / html / tut_exceptions.html .
18 голосов
/ 03 декабря 2014

https://coderwall.com/p/lhkkug/don-t-confuse-ruby-s-throw-statement-with-raise предлагает отличное объяснение, которое, я сомневаюсь, смогу улучшить. Подводя итог, прощупывая некоторые примеры кода из поста в блоге, я продолжаю:

  1. raise / rescue являются наиболее близкими аналогами конструкции throw / catch, с которой вы знакомы по другим языкам (или по raise / except в Python). Если вы столкнулись с ошибкой, и вам нужно throw переписать ее на другом языке, вам следует raise в Ruby.

  2. 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 должны быть вложены ...

    catch :foo do
      catch :bar do
        do_something_that_can_throw_foo_or_bar
      end
    end
    
  • Голый rescue эквивалентен rescue StandardError и является идиоматической конструкцией. «Голый catch», такой как catch() {throw :foo}, никогда ничего не поймает и не должен использоваться.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...