از 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 استثناها را بر [...] توابع تحمیل نمیکند. در عوض، انتخاب بهترین شیوهی ادامه دادن را به عهدهی توسعهدهنده میگذارد.