المسارات
/
Elixir
Elixir
/
التمارين
/
آلة حاسبة RPN
آلة حاسبة RPN

آلة حاسبة RPN

تمرين تعلّمي

مقدمة

الأخطاء

تحدث الأخطاء. في 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

لنفحص هذا التركيب:

  • السطر 1، تُعلَن الكتلة باستخدام try.
  • السطر 2، يوضع هنا نداء الدالة الذي قد يسبّب خطأً، وفي هذه الحالة نستدعي raise/2.
  • السطر 4، في قسم rescue، نطابق النمط على اسم الوحدة للخطأ المرفوع
    • على الجانب الأيسر من ->:
      • يُطابَق e ببنية الخطأ.
      • in كلمة مفتاحية.
      • RuntimeError هو الخطأ الذي نريد الإنقاذ منه.
        • إذا أردنا الإنقاذ من جميع الأخطاء، يمكننا استخدام _ بدلًا من اسم الوحدة أو حذف الكلمة المفتاحية in تمامًا.
    • على الجانب الأيمن:
      • التعليمات التي تُنفَّذ إذا طابق الخطأ.

بنى الأخطاء

الأخطاء (وتُسمى أحيانًا «الاستثناءات») التي تنقذ منها بهذه الطريقة هي بنى. نادرًا ما يتم الإنقاذ من الأخطاء في Elixir. عادةً يُسجَّل الخطأ المنقَذ أو يُرسَل إلى خدمة مراقبة خارجية، ثم يُرفع من جديد. هذا يعني أننا عادةً لا نهتم بالبنية الداخلية لبنية الخطأ المحددة.

في مفهوم الاستثناءات ستتعلم المزيد عن بنى الأخطاء، بما في ذلك كيفية تعريف خطأ مخصص خاص بك.

التعليمات

أثناء عملك في Instruments of Texas، تُكلَّف بالعمل على آلة حاسبة تجريبية بالترميز البولندي المعكوس [RPN] مكتوبة بلغة Elixir. يواجه فريقك مشكلة تتمثل في أن بعض العمليات ترفع أخطاء وتتسبب في انهيار العملية. وقد أُوكلت إليك مهمة كتابة دالة تُغلّف دالة العملية بحيث يمكن التعامل مع الأخطاء بأسلوب أكثر أناقة باستخدام كود Elixir اصطلاحي.

1. حذّر الفريق

نفّذ الدالة 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

أسماء الدوال التي تنتهي بعلامة ! هي تنبيه للمبرمجين إلى أن هذه الدالة قد ترفع خطأ

2. غلّف الخطأ

عند إجراء مزيد من البحث، تلاحظ أن العديد من الدوال تستخدم الذرات والصفوف للإشارة إلى نجاحها أو فشلها. نفّذ 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

3. انقل الرسالة

تحتوي بعض الأخطاء على معلومات مهمة يحتاج زملاؤك في العمل إلى معرفتها لضمان التشغيل الصحيح للنظام. نفّذ 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"}
تعديل عبر GitHub يفتح الرابط في نافذة أو علامة تبويب جديدة
Elixir Exercism

مستعد لبدء آلة حاسبة RPN؟

سجّل في Exercism لتتعلّم وتتقن Elixir عبر 58 مفهومًا168 تمرينًا، وإرشاد بشري حقيقي، وكل ذلك مجانًا.