مقدمة: لماذا مراجعة الكود في Rust ليست مجرد إجراء شكلي
\n\nمراجعة الكود هي إحدى العمليات الرئيسية في تطوير أي برنامج عالي الجودة. ولكن عندما يتعلق الأمر بـ Rust، تكتسب هذه العملية أهمية خاصة. Rust هي لغة ذات نظام فريد للملكية (ownership) والاقتراض (borrowing)، والذي يتحقق منه المترجم في مرحلة الترجمة. ومع ذلك، حتى إذا تم تجميع الكود، فهذا لا يعني أنه مكتوب بشكل جيد وآمن وفعال.
\n\nفي هذه المقالة، سنناقش بالضبط ما يجب الانتباه إليه عند مراجعة كود مشاريع Rust، وكيفية تقديم ملاحظات بناءة حتى لا نسيء إلى الزميل، وكيفية تجنب الأخطاء الشائعة التي لا يكتشفها المترجم. المقال موجه للمطورين الذين هم بالفعل على دراية بأساسيات Rust، ولكنهم يرغبون في تعميق مهاراتهم في المراجعة.
\n\n1. أمان الذاكرة وإدارة الموارد
\n\nيضمن Rust أمان الذاكرة بدون جامع القمامة. لكن هذا لا يلغي الحاجة إلى التحقق من كيفية استخدام المطور لكتل unsafe والمؤشرات الأولية واستدعاءات FFI الخارجية.
ما يجب التحقق منه:
\n- \n
- استخدام
unsafe: يجب تبرير كل كتلةunsafeوتزويدها بتعليق يوضح سبب أمانها. إذا كان من الممكن الاستغناء عنunsafe، فمن الأفضل فعل ذلك. \n - تسرب الموارد: تحقق من تحرير جميع
BoxوRcوArcوالمؤشرات الذكية الأخرى بشكل صحيح. على سبيل المثال، المراجع الدائرية عبرRcبدونWeakهي مشكلة شائعة. \n - ترتيب Drop: إذا كان الهيكل يحتوي على حقول مع تنفيذ مخصص لـ
Drop، فتأكد من أن ترتيب التدمير لا يؤدي إلى أخطاء. \n
// مثال على كود سيء: unsafe بدون تعليقات\nunsafe {\n let ptr = ...;\n // لا يوجد شرح لسبب أمان هذا\n *ptr = 42;\n}\n\n// كود جيد: تعليق وبديل آمن\n// نستخدم unsafe فقط لاستدعاء دالة C تضمن صحة المؤشر\nunsafe {\n // تم الحصول على المؤشر من C API الذي يضمن صحته طوال عمر الاستدعاء\n some_c_function(ptr);\n}\n\n\n2. اصطلاحية الكود والأسلوب
\n\nلدى Rust اصطلاحاتها الخاصة التي تختلف عن C++ أو Python. يجب أن تتحقق مراجعة الكود من مدى توافق الكود مع روح اللغة.
\n\nما يجب التحقق منه:
\n- \n
- استخدام
OptionوResult: تجنبunwrap()وexpect()بدون سبب واضح. في كود الإنتاج، استخدم معالجة الأخطاء عبرmatchأو عامل?أوunwrap_or_else. \n - مطابقة الأنماط: فضل استخدام
if letوmatchبدلاً من سلاسلis_some()/is_ok(). \n - استخدام التريتات: تحقق من تنفيذ التريتات بشكل ذي معنى. على سبيل المثال، يجب أن يعطي تنفيذ
Displayمخرجات قابلة للقراءة، وليس مجردDebug. \n - التسمية: في Rust، من المعتاد استخدام
snake_caseللمتغيرات والدوال، وCamelCaseللأنواع والتريتات. الثوابت —SCREAMING_SNAKE_CASE. \n
// سيء: استخدام مفرط لـ unwrap\nlet value = some_option.unwrap();\n\n// جيد: معالجة الأخطاء\nlet value = match some_option {\n Some(v) => v,\n None => return Err("لم يتم العثور على القيمة".into()),\n};\n\n// أفضل: باستخدام عامل ?\nlet value = some_option.ok_or("لم يتم العثور على القيمة")?;\n\n\n3. الأداء والتخصيصات
\n\nيمنح Rust تحكمًا منخفض المستوى في الذاكرة، لكن هذا لا يعني أن الكود سريع تلقائيًا. في المراجعة، من المهم التحقق من الاختناقات المحتملة.
\n\nما يجب التحقق منه:
\n- \n
- التخصيصات الزائدة: تحقق من عدم إنشاء
StringأوVec