У Ruby є два різних механізми винятків: Throw / Catch та Raise / Rescue.
Чому у нас є дві?
Коли слід використовувати одне, а не друге?
У Ruby є два різних механізми винятків: Throw / Catch та Raise / Rescue.
Чому у нас є дві?
Коли слід використовувати одне, а не друге?
Відповіді:
Я думаю, що http://hasno.info/ruby-gotchas-and-caveats має гідне пояснення різниці:
ловити / кидати - це не те, що піднімати / рятувати. catch / кидок дозволяє швидко виходити з блоків назад до точки, де вилов визначений для конкретного символу, порятунок підняття - це реальна обробка винятків, що стосується об'єкта Exception.
raise
це дуже дорого. throw
не. Подумайте, throw
як використовувати goto
для виходу з петлі.
raise
, fail
, rescue
І ensure
ручки помилки , також відомий як виключенняthrow
і catch
є контрольним потокомНа відміну від інших мов, кидок і ловля Рубі не використовуються для винятку. Натомість вони дають спосіб припинити виконання достроково, коли не потрібно більше подальших робіт. (Грімм, 2011 р.)
Припинення одного рівня керуючого потоку, як while
циклу, може бути виконано простим return
. Припинення багатьох рівнів потоку управління, як і вкладений цикл, можна зробити за допомогою throw
.
Хоча механізм виключення підйому та порятунку чудово підходить для відмови від виконання, коли справи йдуть не так, іноді приємно мати можливість вискочити з якоїсь глибоко вкладеної конструкції під час звичайної обробки. Тут дуже корисно ловити та кидати. (Томас і Хант, 2001)
https://coderwall.com/p/lhkkug/don-t-confuse-ruby-s-throw-statement-with-raise пропонує чудове пояснення, яке я сумніваюся, що можу вдосконалитись. Підводячи підсумок, забираючи декілька зразків коду з допису в блозі:
raise
/ rescue
є найближчими аналогами до throw
/ catch
конструкції, з якою ви знайомі з інших мов (або з Python's raise
/ except
). Якщо ви зіткнулися з умовою помилки, і ви перекладете throw
її на іншій мові, вам слід raise
в Ruby.
Ruby's throw
/ catch
дозволяє вам порушити виконання та піднятися на стек, шукаючи catch
(як raise
/ ні rescue
), але насправді не призначений для умов помилок. Він повинен використовуватися рідко, і чи існує лише тоді, коли catch
поведінка "піднімає стек до тих пір, поки ви не знайдете відповідну " поведінка має сенс для алгоритму, який ви пишете, але не було б сенсу думати про те throw
, що відповідає помилці хвороба.
Для чого використовується Рубі? пропонує кілька пропозицій щодо приємного використання 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}
, ніколи нічого не піймає і не повинен його використовувати.
goto
в C / C ++, як згадував @docwhat, Java позначила перерву та продовження . (Пітон також має відхилену пропозицію щодо цього.)