يمكن استخدام 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 الاستثناءات على الدوال [...]. وبدلًا من ذلك، تترك للمطوّر اختيار أفضل طريقة للمضي قدمًا.