За допомогою try .. rescue можна перехоплювати та опрацьовувати помилки, які виникають усередині блоку.
Наприклад:
try do
raise RuntimeError, "error"
rescue
e in RuntimeError -> :error
end
try.raise/1.rescue ми зіставляємо за зразком назву модуля помилки, яку було викликано
->:
e зіставляється зі структурою помилки.in - це ключове слово.RuntimeError - це модуль, з яким зіставляємо, але зіставляти можна з будь-яким модулем помилки, або з _, щоб зіставити всі помилки.Помилки (які іноді також називають «винятками»), які ми перехоплюємо в такий спосіб, - це структури. Різні структури помилок мають різні ключі. У розділі «Винятки» стандартної бібліотеки можна знайти перелік усіх наперед визначених помилок.
# ArithmeticError caused by division by zero
%ArithmeticError{message: "bad argument in arithmetic expression"}
# Protocol.UndefinedError caused by passing `nil` to `Enum.count/1`
%Protocol.UndefinedError{description: "", protocol: Enumerable, value: nil}
Перехоплення помилок в Elixir трапляється дуже рідко. Зазвичай перехоплену помилку записують у журнал або надсилають у зовнішню службу моніторингу, а потім викликають знову. Це означає, що зазвичай нас не цікавить внутрішня будова конкретної структури помилки.
Концепція винятків описує, як визначати власні структури помилок.
Уникаймо програмних прийомів, які використовують помилки для керування логікою виконання. В Elixir це антипатерн.
# Avoid using errors for control-flow.
try do
{:ok, value} = MyModule.janky_function()
"All good! #{value}."
rescue
e in RuntimeError ->
reason = e.message
"Uh oh! #{reason}."
end
# Rather, use control-flow structures for control-flow.
case MyModule.janky_function() do
{:ok, value} -> "All good! #{value}."
{:error, reason} -> "Uh oh! #{reason}."
end
Як сказано в посібнику з початку роботи з Elixir:
Рішення про те, чи є помилка під час [виконання дії] винятковою, ухвалює сам застосунок. Саме тому Elixir не навʼязує винятків [...] функціям. Натомість він залишає розробникові вибір, як діяти найкраще.