تحدث الأخطاء. في Elixir، ورغم أن الناس كثيرًا ما يقولون «دعه ينهار»، فهناك أوقات نحتاج فيها إلى إنقاذ نداء الدالة وإعادته إلى حالة سليمة معروفة للوفاء بعقد برمجي. في بعض اللغات، تُستخدم الأخطاء كأسلوب للتحكم في مسار التنفيذ، لكن هذا النمط غير مستحسن في Elixir. وغالبًا ما نستطيع تمييز الدوال التي قد ترفع خطأً من اسمها وحده: الدوال التي ترفع الأخطاء ينتهي اسمها بـ !. وهذا بالمقارنة مع الدوال التي تُرجع {:ok, value} أو :error. انظر إلى أمثلة المكتبة هذه:
Map.fetch(%{a: 1}, :b)
# => :error
Map.fetch!(%{a: 1}, :b)
# => raises KeyError
توفّر Elixir تركيبًا للإنقاذ من الأخطاء باستخدام try .. rescue
try do
raise RuntimeError, "error"
rescue
e in RuntimeError -> :error
end
لنفحص هذا التركيب:
try.raise/2.rescue، نطابق النمط على اسم الوحدة للخطأ المرفوع
->:
e ببنية الخطأ.in كلمة مفتاحية.RuntimeError هو الخطأ الذي نريد الإنقاذ منه.
_ بدلًا من اسم الوحدة أو حذف الكلمة المفتاحية in تمامًا.الأخطاء (وتُسمى أحيانًا «الاستثناءات») التي تنقذ منها بهذه الطريقة هي بنى. نادرًا ما يتم الإنقاذ من الأخطاء في Elixir. عادةً يُسجَّل الخطأ المنقَذ أو يُرسَل إلى خدمة مراقبة خارجية، ثم يُرفع من جديد. هذا يعني أننا عادةً لا نهتم بالبنية الداخلية لبنية الخطأ المحددة.
في مفهوم الاستثناءات ستتعلم المزيد عن بنى الأخطاء، بما في ذلك كيفية تعريف خطأ مخصص خاص بك.
أثناء عملك في Instruments of Texas، تُكلَّف بالعمل على آلة حاسبة تجريبية بالترميز البولندي المعكوس [RPN] مكتوبة بلغة Elixir. يواجه فريقك مشكلة تتمثل في أن بعض العمليات ترفع أخطاء وتتسبب في انهيار العملية. وقد أُوكلت إليك مهمة كتابة دالة تُغلّف دالة العملية بحيث يمكن التعامل مع الأخطاء بأسلوب أكثر أناقة باستخدام كود Elixir اصطلاحي.
نفّذ الدالة calculate!/2 لاستدعاء دالة العملية مع تمرير المكدس كوسيط وحيد. دالة العملية معرّفة في مكان آخر، لكنك تعرف أنها إما أن تكتمل بنجاح أو ترفع خطأ.
stack = []
operation = fn _ -> :ok end
RPNCalculator.calculate!(stack, operation)
# => :ok
stack = []
operation = fn _ -> raise ArgumentError, "An error occurred" end
RPNCalculator.calculate!(stack, operation)
# => ** (ArgumentError) An error occurred
أسماء الدوال التي تنتهي بعلامة
!هي تنبيه للمبرمجين إلى أن هذه الدالة قد ترفع خطأ
عند إجراء مزيد من البحث، تلاحظ أن العديد من الدوال تستخدم الذرات والصفوف للإشارة إلى نجاحها أو فشلها. نفّذ calculate/2 باستخدام هذه الاستراتيجية.
stack = []
operation = fn _ -> "operation completed" end
RPNCalculator.calculate(stack, operation)
# => {:ok, "operation completed"}
stack = []
operation = fn _ -> raise ArgumentError, "An error occurred" end
RPNCalculator.calculate(stack, operation)
# => :error
تحتوي بعض الأخطاء على معلومات مهمة يحتاج زملاؤك في العمل إلى معرفتها لضمان التشغيل الصحيح للنظام. نفّذ calculate_verbose/2 لنقل رسالة الخطأ. الخطأ عبارة عن بنية تحتوي على حقل :message.
stack = []
operation = fn _ -> "operation completed" end
RPNCalculator.calculate_verbose(stack, operation)
# => {:ok, "operation completed"}
stack = []
operation = fn _ -> raise ArgumentError, "An error occurred" end
RPNCalculator.calculate_verbose(stack, operation)
# => {:error, "An error occurred"}
سجّل في Exercism لتتعلّم وتتقن Elixir عبر 58 مفهومًا168 تمرينًا، وإرشاد بشري حقيقي، وكل ذلك مجانًا.