У 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
тоді як декілька catches потрібно вкладати ...
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 позначила перерву та продовження . (Пітон також має відхилену пропозицію щодо цього.)