Вот конкретный вариант использования else
в выражении begin
. Предположим, вы пишете автоматизированные тесты и хотите написать метод, который возвращает ошибку, вызванную блоком. Но вы также хотите, чтобы тест не прошел, если блок не вызывает ошибку. Вы можете сделать это:
def get_error_from(&block)
begin
block.call
rescue => err
err # we want to return this
else
raise "No error was raised"
end
end
Обратите внимание, что вы не можете переместить raise
внутри блока begin
, потому что он получит rescue
d. Конечно, есть и другие способы без использования else
, например, проверка, является ли err
nil
после end
, но это не так кратко.
Лично я редко использую else
таким образом, потому что я думаю, что он редко нужен, но в таких редких случаях он пригодится.
EDIT
Другой случай использования произошел со мной. Вот типичный begin
/ rescue
:
begin
do_something_that_may_raise_argument_error
do_something_else_when_the_previous_line_doesnt_raise
rescue ArgumentError => e
handle_the_error
end
Почему это не идеально? Потому что намерением является rescue
, когда do_something_that_may_raise_argument_error
поднимает ArgumentError
, не , когда do_something_else_when_the_previous_line_doesnt_raise
поднимает.
Обычно лучше использовать begin
/ rescue
для переноса минимального кода, который вы хотите защитить от raise
, потому что в противном случае:
- вы можете маскировать ошибки в коде, который не должен был
raise
- намерение
rescue
труднее расшифровать. Кто-то (включая вашу будущую личность) может прочитать код и спросить: «Какое выражение я хотел защитить? Это выглядит как выражение ABC ... но, возможно, выражение DEF тоже ????» Что задумал автор ?!» Рефакторинг становится намного сложнее.
Вы избежите этих проблем с этим простым изменением:
begin
do_something_that_may_raise_argument_error
rescue ArgumentError => e
handle_the_error
else
do_something_else_when_the_previous_line_doesnt_raise
end