كل الأخطاء في Elixir تُطبّق سلوك الاستثناء. وكما في سلوك الوصول، يحدّد سلوك الاستثناء دوال استدعاء راجعة يجب على الوحدة تنفيذها لتفي بالعقد البرمجي لهذا السلوك. وبمجرد تعريف خطأ، تكون له الخصائص التالية:
:message.raise/1 وraise/2 لرفع الخطأ المقصوديحدّد سلوك الاستثناء أيضًا دالتَي استدعاء راجعتين: message/1 وexception/1. وإذا لم تُنفَّذ، ستُستخدم تنفيذات افتراضية. تحوّل message/1 بنية الخطأ إلى رسالة مقروءة عند استدعائها مع raise. وتتيح exception/1 إضافة سياق إضافي إلى الرسالة عند استدعائها مع raise/2.
لتعريف استثناء انطلاقًا من وحدة خطأ، نستخدم ماكرو defexception:
# Defines a minimal error, with the name `MyError`
defmodule MyError do
defexception message: "error"
end
# Defines an error with a customized exception/1 function
defmodule MyCustomizedError do
defexception message: "custom error"
@impl true
def exception(value) do
case value do
[] ->
%MyCustomizedError{}
_ ->
%MyCustomizedError{message: "Alert: " <> value}
end
end
end
يمكن استخدام الأخطاء المعرّفة مثل خطأ مدمج باستخدام raise/1 أو raise/2.
raise/1 يرفع خطأً محددًا باسم وحدته، وإذا كان الوسيط سلسلة نصية، فإنه يرفع RuntimeError وتكون هذه السلسلة النصية هي رسالته.raise/2 يرفع خطأً محددًا باسم وحدته، ويقبل وسيط سمات يُستخدم للحصول على الخطأ بالرسالة المناسبة.بينما تواصل عملك في Instruments of Texas، هناك تقدم يُحرز في تنفيذ Elixir لآلة حاسبة RPN. يرغب فريقك في أن يكون قادرًا على رفع أخطاء أكثر تحديدًا من الأخطاء العامة التي توفرها المكتبة القياسية. أنت تجري بعض البحث، لكنك قررت تنفيذ خطأين جديدين يطبقان سلوك الاستثناء.
قسمة عدد على صفر تنتج نتيجة غير معرّفة، ويرى الفريق أن تمثيلها الأفضل يكون بخطأ.
نفّذ الوحدة DivisionByZeroError لتحتوي على رسالة الخطأ: "division by zero occurred"
raise DivisionByZeroError
# => ** (DivisionByZeroError) division by zero occurred
تستخدم آلات حاسبة RPN مكدسًا لتتبع الأعداد قبل جمعها. يمثّل الفريق هذا المكدس بمصفوفة من الأعداد (صحيحة وعشرية)، مثل: [3, 4.0]. تحتاج كل عملية إلى عدد محدد من الأعداد على المكدس لتنفيذ حسابها. عندما لا توجد أعداد كافية على المكدس، يُسمى هذا خطأ نقص المكدس. نفّذ الاستثناء StackUnderflowError الذي يوفر رسالة افتراضية، وسياقًا إضافيًا اختياريًا
raise StackUnderflowError
# => ** (StackUnderflowError) stack underflow occurred
raise StackUnderflowError, "when dividing"
# => ** (StackUnderflowError) stack underflow occurred, context: when dividing
نفّذ الدالة divide/1 التي تأخذ مكدسًا (مصفوفة من عددين) وتقوم بما يلي:
RPNCalculator.Exception.divide([])
# => ** (StackUnderflowError) stack underflow occurred, context: when dividing
RPNCalculator.Exception.divide([0, 100])
# => ** (DivisionByZeroError) division by zero occurred
RPNCalculator.Exception.divide([4, 16])
# => 4
لاحظ أن ترتيب المصفوفة معكوس!
سجّل في Exercism لتتعلّم وتتقن Elixir عبر 58 مفهومًا168 تمرينًا، وإرشاد بشري حقيقي، وكل ذلك مجانًا.