Я действительно не вижу разумного использования для них. Есть уже rescue
и raise
, поэтому зачем нужны throw
и catch
? Кажется, они, как предполагается, используются, чтобы выпрыгнуть из глубокого гнездования, но это просто пахнет как goto для меня. Есть ли примеры хорошего, чистого использования для них?
Где улов и бросок полезны в Ruby?
Ответ 1
Примечание. Похоже, что некоторые вещи изменились с помощью catch/throw в 1.9. Этот ответ относится к Ruby 1.9.
Большая разница заключается в том, что вы можете throw
что-нибудь, а не только вещи, которые получены из StandardError
, в отличие от raise
. Что-то глупое, как это, является законным, например:
throw Customer.new
но это не очень важно. Но вы не можете этого сделать:
irb(main):003:0> raise Customer.new
TypeError: exception class/object expected
from (irb):3:in `raise'
from (irb):3
from /usr/local/bin/irb:12:in `<main>'
Ответ 2
Они могут быть действительно полезны для упрощения DSL для конечных пользователей путем передачи управления из DSL без необходимости в сложных операторах case/if
У меня есть приложение Ruby, которое позволяет пользователям расширять его через внутренний DSL. Некоторые функции в DSL должны возвращать управление определенным частям моего приложения. Возьмем простой пример. Предположим, что пользователь разрабатывает простое расширение относительно дат
if today is a holiday then
do nothing
end
week_of_year = today.week.number
if week_of_year < 10 then
...
Бит do nothing
запускает бросок, который передает управление из инструкции exec и обратно ко мне.
Вместо того, чтобы продолжать выполнять DSL, в каком-то состоянии мы хотим, чтобы он выходил и отдавал управление моему приложению. Теперь вы можете заставить пользователя использовать множество встроенных операторов if и иметь DSL-конец, но это просто затмевает то, что пытается сказать логика.
Throw действительно является goto, который считается "опасным", но, черт возьми, иногда это лучшее решение.
Ответ 3
Это, в основном, goto и немного более сродни вызову /cc, за исключением того, что поток управления подключается неявно по имени, а не явно как параметр. Разница между throw/catch и повышением/спасением заключается в том, что первая предназначена для использования в потоке управления, а не только в исключительных ситуациях, и не тратит время на сбор трассировки стека.
Sinatra использует команды throw/catch для кодов ошибок HTTP, где обработчик может использовать бросок для управления уступкой библиотеке Sinatra структурированным способом. Другие виды фреймворков HTTP используют исключения или возвращают другой класс ответа, но это позволяет Sinatra (например) попробовать другой обработчик запроса после его поиска.
Ответ 4
Разница между двумя заключается в том, что вы можете только "поднимать" исключения, но можете "бросить" что угодно (1.9). Помимо этого, они должны быть взаимозаменяемыми, т.е. Следует переписывать одно с другим, как пример, приведенный @john-feminella.