Где ловить и бросать полезно в Ruby? - PullRequest
10 голосов
/ 07 января 2010

Я действительно не вижу вменяемого использования для них. Уже есть rescue и raise, так зачем нужны throw и catch? Кажется, они должны быть использованы, чтобы выпрыгнуть из глубокого вложения, но для меня это просто пахнет как гото. Есть ли примеры хорошего, чистого использования для них?

Ответы [ 4 ]

6 голосов
/ 07 января 2010

Примечание: Похоже, что некоторые вещи изменились с броском / броском в 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>'
5 голосов
/ 07 января 2010

Они могут быть действительно полезны для упрощения 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, но это просто затеняет то, что пытается сказать логика.

Бросок - это действительно goto, который считается «опасным», но, черт возьми, иногда они являются лучшим решением.

2 голосов
/ 07 января 2010

Это в основном goto, и немного больше похоже на call / cc, за исключением того, что поток управления связан неявно по имени, а не явно как параметр. Разница между броском / захватом и повышением / спасением заключается в том, что первый предназначен для использования в качестве потока управления, а не только в исключительных ситуациях, и он не тратит время на составление трассировки стека.

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

1 голос
/ 07 января 2010

Разница между ними состоит в том, что вы можете только «поднять» исключения, но можете «выбросить» что угодно (1.9). Кроме этого, они должны быть взаимозаменяемыми, то есть должна быть возможность переписывать друг друга, как в примере, приведенном @ john-feminella.

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