В чем разница между Raising Exceptions vs Throwing Exceptions в Ruby?

Ruby имеет два разных механизма исключения: Throw/Catch and Raise/Rescue.

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

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

Ответ 1

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

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

Ответ 2

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

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

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

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

Ссылки

Ответ 3

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 throw/catch позволяет вам выполнить выполнение и поднять стек, ищущий catch (например, raise/rescue), но на самом деле не предназначен для условий ошибки, Его следует использовать редко, и существует только тот момент, когда "подойти к стеку, пока вы не найдете соответствующее поведение catch", имеет смысл для алгоритма, который вы пишете, но не имеет смысла думать о throw как соответствующее условию ошибки.

    Что такое 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}, никогда ничего не поймает и не должен использоваться.